当派生类继承n个基类的每个属性具有一个虚函数时,在为派生类构造虚拟表时,为什么编译器为每个基类构造一个单独的虚拟表?为什么编译器不构造一个单个虚拟表,该虚拟表包含对Base类及其自身的虚函数的所有引用?
例如:
在下面的程序中,派生类继承了3个基类,每个基类具有一个虚函数。
class Base1
{
public:
virtual void base1_func1(){cout<<"In Base1:base1_func1:"<<endl;}
};
class Base2
{
public:
virtual void base2_func1(){cout<<"In Base2:base2_func1:"<<endl;}
};
class Base3
{
public:
virtual void base3_func1(){cout<<"In Base3:base3_func1:"<<endl;}
};
class Derived:public Base1, public Base2, public Base3
{
};
typedef void (*Func) (void);
int main()
{
Base1 b1;
Base2 b2;
Base3 b3;
Derived d;
Func f= NULL;
cout<<"Size of Base1 obj:"<<sizeof(b1)<<endl;
cout<<"Size of Base2 obj:"<<sizeof(b2)<<endl;
cout<<"Size of Base3 obj:"<<sizeof(b3)<<endl;
cout<<"Size of Derived obj:"<<sizeof(d)<<endl;
cout<<"Printing the VPTR Address of Base1 obj b1 :"<< *((int *)(&b1)+0)<<endl;
cout<<"Printing the Address of Base1 func1 in VTABLE:"<< (int *)*((int *)*((int *)(&b1)+0)+0)<<endl;
f = (Func)*((int *)*((int *)(&b1)+0)+0);
f();
cout<<"Printing the VPTR Address of Base2 obj b2 :"<< *((int *)(&b2)+0)<<endl;
cout<<"Printing the Address of Base2 func1 in VTABLE:"<< (int *)*((int *)*((int *)(&b2)+0)+0)<<endl;
f = (Func)*((int *)*((int *)(&b2)+0)+0);
f();
cout<<"Printing the VPTR Address of Base3 obj b3 :"<< *((int *)(&b3)+0)<<endl;
cout<<"Printing the Address of Base3 func1 in VTABLE:"<< (int *)*((int *)*((int *)(&b3)+0)+0)<<endl;
f = (Func)*((int *)*((int *)(&b3)+0)+0);
f();
cout<<"Printing the VPTR1 Address of Derived obj d :"<< *((int *)(&d)+0)<<endl;
cout<<"Printing the VPTR2 Address of Derived obj d :"<< *((int *)(&d)+1)<<endl;
cout<<"Printing the VPTR3 Address of Derived obj d :"<< *((int *)(&d)+2)<<endl;
cout<<"Printing the Address of Derived base1_func1 in VTABLE:"<< (int *)*((int *)*((int *)(&d)+0)+0)<<endl;
f = (Func)*((int *)*((int *)(&d)+0)+0);
f();
cout<<"Printing the Address of Derived base2_func1 in VTABLE:"<< (int *)*((int *)*((int *)(&d)+1)+0)<<endl;
f = (Func)*((int *)*((int *)(&d)+1)+0);
f();
cout<<"Printing the Address of Derived base3_func1 in VTABLE:"<< (int *)*((int *)*((int *)(&d)+2)+0)<<endl;
f = (Func)*((int *)*((int *)(&d)+2)+0);
f();
return 0;
}
Output:
Size of Base1 obj:4
Size of Base2 obj:4
Size of Base3 obj:4
Size of Derived obj:12
Printing the VPTR Address of Base1 obj b1 :134517392
Printing the Address of Base1 func1 in VTABLE:0x8048dfe
In Base1:base1_func1:
Printing the VPTR Address of Base2 obj b2 :134517424
Printing the Address of Base2 func1 in VTABLE:0x8048e2a
In Base2:base2_func1:
Printing the VPTR Address of Base3 obj b3 :134517456
Printing the Address of Base3 func1 in VTABLE:0x8048e56
In Base3:base3_func1:
Printing the VPTR1 Address of Derived obj d :134517512
Printing the VPTR2 Address of Derived obj d :134517524
Printing the VPTR3 Address of Derived obj d :134517536
Printing the Address of Derived base1_func1 in VTABLE:0x8048dfe
In Base1:base1_func1:
Printing the Address of Derived base2_func1 in VTABLE:0x8048e2a
In Base2:base2_func1:
Printing the Address of Derived base3_func1 in VTABLE:0x8048e56
In Base3:base3_func1:
输出清楚地表明,complier为派生类中继承的每个Base类构造一个单独的虚拟表。
最佳答案
我可能会错过一些东西,但不会:
cout<<"Printing the VPTR1 Address of Derived obj d :"<< *((int *)(&d)+0)<<endl;
cout<<"Printing the VPTR2 Address of Derived obj d :"<< *((int *)(&d)+1)<<endl;
cout<<"Printing the VPTR3 Address of Derived obj d :"<< *((int *)(&d)+2)<<endl;
您只是在打印“X” d元素的地址。
&d
= d的地址(&d + X)
=继续到X元素,即+ (X * sizeof(d))
(int *)(&d + X)
=将此地址视为指向int的指针(而不是指向d的指针)*((int *)(&d + 2)
=获取int值(基本上是地址的值)。我的意思是,如果您将更多私有(private)成员添加到
Derived
类中,并且通过增加sizeof(d)
您将获得不同的值,但是很明显VPTR并没有移动。==编辑==
不确定如何操作,但是您需要找到正确的方法来找到VPTR地址
关于c++ - 通过编译器构建虚拟表,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9312389/