当派生类继承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/

10-12 15:01