Virtual function table)

Source: Internet
Author: User

Test site: "dll hell"
Frequency:★★
Answer:
"Dll hell" mainly refers to DLL (Dynamic Link Library) version conflicts. Under normal circumstances, the new version of DLL will overwrite the old version, so the application that used the old version of dll will not continue to work normally.
 
Extended knowledge: virtual function table
We all know that Virtual functions are implemented through a Virtual Table. In this table, it is mainly an address table of class virtual functions. This table solves the inheritance and overwrite issues, and its content truly reflects the actual functions. In this way, the table is allocated to the memory of the instance in instances of classes with virtual functions. Therefore, when the parent class pointer is used to operate a subclass, this virtual function table is especially important. Like a map, it specifies the actually called function.
In the standard specification of C ++, the compiler must ensure that the pointer to the virtual function table exists in the front of the object instance (this is to ensure that the offset of the virtual function is obtained correctly ). This means that the virtual function table is obtained through the address of the object instance, and then the function pointer can be traversed and the corresponding function can be called. See the following program example:
1 # include <iostream>
2 using namespace std;
3
4 class Base
5 {
6 public:
7 virtual void fun1 () {cout <"Base: fun1" <endl ;}
8 virtual void fun2 () {cout <"Base: fun2" <endl ;}
9 virtual void fun3 () {cout <"Base: fun3" <endl ;}
10 private:
11 int num1;
12 int num2;
13 };
14
15 typedef void (* Fun) (void );
16
17 int main ()
18 {
19 Base B;
20 Fun pFun;
21
22 pFun = (Fun) * (int *) (& B) + 0); // get Base: fun1 () Address
23 pFun (); // execute Base: fun1 ()
24 pFun = (Fun) * (int *) (& B) + 1); // get Base: fun1 () Address
25 pFun (); // execute Base: fun2 ()
26 pFun = (Fun) * (int *) (& B) + 2); // get Base: fun1 () Address
27 pFun (); // execute Base: fun3 ()
28
29 return 0;
30}
The execution result of the above program is as follows:
1 Base: fun1
2 Base: fun2
3 Base: fun3
The function pointer pFun is used to call three virtual functions of object B. Through this example, we can forcibly convert & B to int * to obtain the address of the virtual function table. Then, we can obtain the address of the first virtual function by taking the address again, that is, Base: fun1 (). If you want to call Base: fun2 () and Base: fun3 (), you only need to add the offset of the array element to & B. The subsequent steps are similar.
The B memory structure of the Base Object in the program, as shown in Figure 9.3.

& Bp

Vfptr
Num1
Num2
 
 

Base: fun1 () Base: fun2 () Base: fun3 () NULL

Figure 9.3 Base virtual function table
How many virtual function tables does a class have?
For a single-inherited class, if it has a virtual function, there is only one virtual function table. For multiple inherited classes, it may have multiple virtual function tables.
Consider the definitions of classes in the following code:
1 # include <iostream>
2 using namespace std;
3
4 class Base1
5 {
6 public:
7 Base1 (int num): num_1 (num ){}
8 virtual void foo1 () {cout <"Base1: foo1" <num_1 <endl ;}
9 virtual void foo2 () {cout <"Base1: foo2" <num_1 <endl ;}
10 virtual void foo3 () {cout <"Base1: foo3" <num_1 <endl ;}
11 private:
12 int num_1;
13 };
14
15 class Base2
16 {
17 public:
18 Base2 (int num): num_2 (num ){}
19 virtual void foo1 () {cout <"Base2: foo1" <num_2 <endl ;}
20 virtual void foo2 () {cout <"Base2: foo2" <num_2 <endl ;}
21 virtual void foo3 () {cout <"Base2: foo3" <num_2 <endl ;}
22 private:
23 int num_2;
24 };
25
26 class Base3
27 {
28 public:
29 Base3 (int num): num_3 (num ){}
30 virtual void foo1 () {cout <"Base3: foo1" <num_3 <endl ;}
31 virtual void foo2 () {cout <"Base3: foo2" <num_3 <endl ;}
32 virtual void foo3 () {cout <"base3: foo3" <num_3 <Endl ;}
33 private:
34 int num_3;
35 };
36
37 class derived1: Public base1
38 {
39 public:
40 derived1 (INT num): base1 (Num ){}
41 virtual void faa1 () {cout <"derived1: faa1" <Endl;} // No Overwrite
42 virtual void faa2 () {cout <"Derived1: faa2" <endl ;}
43 };
44
45 class Derived2: public Base1
46 {
47 public:
48 Derived2 (int num): Base1 (num ){}
49 virtual void foo2 () {cout <"Derived2: foo2" <endl;} // only covers Base1: foo2
50 virtual void fbb2 () {cout <"Derived2: fbb2" <endl ;}
51 virtual void fbb3 () {cout <"derived2: fbb3" <Endl ;}
52 };
53
54 class derived3: Public base1, public base2, public base3 // multi-inheritance, no Overwrite
55 {
56 public:
57 derived3 (INT num_1, int num_2, int num_3 ):
58 base1 (num_1), base2 (num_2), base3 (num_3 ){}
59 virtual void f105() {cout <"derived3: fcc1." <Endl ;}
60 virtual void fcc2 () {cout <"Derived3: fcc2" <endl ;}
61 };
62
63 class Derived4: public Base1, public Base2, public Base3 // multiple inheritance with Overwrite
64 {
65 public:
66 Derived4 (int num_1, int num_2, int num_3 ):
67 Base1 (num_1), Base2 (num_2), Base3 (num_3 ){}
68 virtual void foo1 () {cout <"Derived4: foo1" <endl;} // overwrites Base1: foo1,
69 // Base2: foo1, Base3: foo1
70 virtual void fdd () {cout <"Derived4: frr" <endl ;}
71 };
This example illustrates the virtual function tables under four inheritance conditions.
(1) General inheritance (no virtual function coverage): The Derived1 class inherits from the Base1 class, as shown in table 9.4 of the Derived1 virtual function.

Vfptr

Base1: foo1 ()

Base1: foo2 ()

Base1: foo3 ()

NULL

Figure 9.4 Derived1 virtual function table
The derived1 class does not have any function that overwrites the base class base1. Therefore, the two virtual functions faa1 () and faa2 () are added to the end of the virtual function table in sequence.
(2) General inheritance (with virtual function overwrite): The derived2 class inherits from the base1 class and overwrites the virtual function foo2 () in the base1 class. The virtual function table 9.5 of derived2 shows.

Vfptr

Base1: faa3 ()

Derived2: fbb2 ()

Derived2: fbb3 ()

Null

Derived2: foo2 ()

Base1: foo1 ()

Figure 9.5 derived2 virtual function table
Derived2 overwrites faa1 () of base1. Therefore, in its virtual function table, derived2: foo2 () replaces base1: foo2 (), fbb2 (), and fbb3 () added to the end of the virtual function table in sequence.
(3) Multi-inheritance (no virtual function coverage): The derived3 class inherits from the base1 class, base2 class, And base3 class, as shown in table 9.6 of the derived3.

Vfptr
(Base1)

Base1: foo1 ()

Base1: foo2 ()

Base1: foo3 ()

Derived3: fpc3 ()

Derived3: fcc2 ()
 

Null

Vfptr
(Base2)

Vfptr
(Base3)

Base2: foo1 ()

Base2: foo2 ()

Base2: foo3 ()

Null

Base3: foo3 ()

Null

Base3: foo1 ()

Base3: foo2 ()

Figure 9.6 derived3 virtual function table
Each parent class has its own virtual table, and derived3 has three virtual tables, and the member functions fcc2 () and fcc2 () are placed in the first parent class (base1) the first parent class is determined in the declared order. In this way, the actual function can be called to resolve the pointer of different parent classes pointing to the same subclass instance. For example:
1 base2 * pbase2 = new derived3 ();
2 pbase2-> foo2 (); // call base2: foo2 ()
Point the base2 type pointer to the derive3 instance, then the call will correspond to those functions in the base2 virtual table.
(4) Multi-inheritance (with virtual function coverage): The derived4 class inherits from the base1 class, base2 class, And base3 class, And foo1 () of the foo1 () and base2 classes of the base1 class () and foo1 () of the base3 class are overwritten. The virtual function table 9.7 of derived4 is shown in.
 

Vfptr
(Base1)

Derived4: foo1 ()

Base1: foo2 ()

Base1: foo3 ()

Derived4: FDD ()

Null

Vfptr
(Base2)

Vfptr
(Base3)

Derived4: foo1 ()

Base2: foo2 ()

Base2: foo3 ()

Null

Base3: foo3 ()

Null

Derived4: foo1 ()

Base3: foo2 ()

Figure 9.7 Derived4 virtual function table
We can see that Base1: foo1 (), Base2: foo1 (), and Base3: foo1 () are replaced with Derived: foo1 (). In this way, we can point any static parent class to the subclass and call the f () of the subclass. For example:
1 Base1 * pBase1 = new Derived4 ();
2 pBase1-> foo1 (); // call Derived4: foo1 () in the virtual table inherited from Base1 ()
The following is the test code for the four inheritance cases we have discussed:
1 int main ()
2 {
3 Base1 * pBase1 = NULL;
4 Base2 * pBase2 = NULL;
5 Base3 * pBase3 = NULL;
6
7 cout <"----- generally inherited from Base1 without overwriting ----------" <endl;
8 Derived1 d1 (1); // Derived1 is generally inherited from Base1 without overwriting.
9 pBase1 = & d1;
10 pBase1-> foo1 (); // execute Base1: foo1 ();
11
12 cout <"----- generally inherited from Base1, covering foo2 () ---------" <endl;
13 Derived2 d2 (2); // Derived2 is generally inherited from Base1, covering Base1: foo2 ()
14 pBase1 = & d2;
15 pBase1-> foo2 (); // run Derived2: foo2 ();
16
17 cout <"----- multi-inheritance without overwriting ----------" <endl;
18 derived3 D3 (1, 2, 3); // derived3 multi-inheritance from base1, base2, base3, not covered
19 pbase1 = & D3;
20 pbase2 = & D3;
21 pbase3 = & D3;
22 pbase1-> foo1 (); // execute base1: foo1 ();
23 pbase2-> foo1 (); // execute base2: foo1 ();
24 pbase3-> foo1 (); // execute base3: foo1 ();
25
26 cout <"------ multi-inheritance, covering foo1 () ---------" <endl;
27 Derived4 d4 (1, 2, 3); // Derived4 multi-inheritance from Base1, Base2, Base3, overwrite foo1 ()
28 pBase1 = & d4;
29 pBase2 = & d4;
30 pBase3 = & d4;
31 pBase1-> foo1 (); // run Derived4: foo1 ();
32 pBase2-> foo1 (); // run Derived4: foo1 ();
33 pBase3-> foo1 (); // run Derived4: foo1 ();
34 return 0;
35}
The test results are as follows:
1 is generally inherited from Base1 and does not cover ----------
2 Base1: foo1 1
3. It is generally inherited from Base1 and overwrites foo2 ()
4 Derived2: foo2
5 ----- multi-inheritance, no coverage ----------
6 Base1: foo1 1
7 Base2: foo1 2
8 Base3: foo3 3
9 ------ multi-inheritance, covering foo1 ()---------
10 Derived4: foo1
11 Derived4: foo1
12 Derived4: foo1

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.