一、指向虚函数表的指针(vfptr)是被添加在最前面的,而在虚函数表里面,各个虚函数是按照其声明的顺序排列的。
为了验证,同样的在上面的例子里修改,直接添加一个虚函数进去:
#include
using namespace std;
class A{
private:
char ch;
int a,b;
public:
A(){
cout<<"调用构造函数\n";
a=2;
b=3;
}
~A(){
cout<<"调用析构函数\n";
}
void display(){
cout<<"a+b="< }
virtual void display1(){
cout<<"virtual function: display1()\n";
}
};
int main(){
A a;
a.display();
a.display1();
return 0;
}
同样通过命令行编译:
E:\Programming\c_cpp>cl classA.cpp /EHsc /d1reportAllClassLayout > class.layout
从重定向的class.Layout文件中获得:
class A size(16):
+---
0 | {vfptr}
4 | ch
| <alignment member> (size=3)
8 | a
12 | b
+---
A::$vftable@:
| &A_meta
| 0
0 | &A::display1
A::display1 this adjustor: 0
二、当一个类是继承另一个类的话或多个类的话,派生类将每个基类都嵌入了自身,而且每个基类还都保留有自己的虚函数表。但是请注意,第一个基类的虚函数表是被派生类共享的,派生类的虚函数将会被例在基类虚函数表的后面。
同样是在上面的代码的基础上进行一翻修改:
#include
using namespace std;
class A{
private:
char ch;
int a,b;
public:
virtual void displayA(){
cout<<"virtual function: displayA()\n";
}
};
class B{
private:
char ch;
int a,b;
public:
virtual void displayB(){
cout<<"virtual function: displayB()\n";
}
};
class C: public A,public B{
private:
int a,b;
public:
void displayC(){
cout<<"function: displayC()\n";
}
};
int main(){
C c;
c.displayA();
c.displayB();
c.displayC();
return 0;
}
编译后得到class.Layout文件:
class A size(16):
+---
0 | {vfptr}
4 | ch
| <alignment member> (size=3)
8 | a
12 | b
+---
A::$vftable@:
| &A_meta
| 0
0 | &A::displayA
A::displayA this adjustor: 0
class B size(16):
+---
0 | {vfptr}
4 | ch
| <alignment member> (size=3)
8 | a
12 | b
+---
B::$vftable@:
| &B_meta
| 0
0 | &B::displayB
B::displayB this adjustor: 0
这里的我们上面已经理解并实践后,我们这里主要是关注类C的结构:
class C size(40):
+---
| +--- (base class A)
0 | | {vfptr}
4 | | ch
| | <alignment member> (size=3)
8 | | a
12 | | b
| +---
| +--- (base class B)
16 | | {vfptr}
20 | | ch
| | <alignment member> (size=3)
24 | | a
28 | | b
| +---
32 | a
36 | b
+---
C::$vftable@A@:
| &C_meta
| 0
0 | &A::displayA
C::$vftable@B@:
| -16
0 | &B::displayB
留意了一下,发现嵌入的顺序也是按照继续的从左到右的顺序来的!