Liny_@NotePad

沉迷ACG中

多重继承的虚函数表与类型转换

YOYO posted @ 2009年8月21日 19:52 in 【C/C++】 with tags 虚函数表 类型转换 , 3834 阅读

总结:

  • 非virtual继承:
    进行隐式转换或进行显式转换均可时(代码中简写为隐式强转),最左父类指针指向子类时指向地址不变,其他父类指针指向子类时指向地址需要偏移,根据指针的类型对虚函数进行地址偏移(访问指针类型对象的虚函数表)。
    必须进行显式转换时指针指向地址均不变,按照强制转换前的类型对虚函数进行地址偏移(访问原来类型的虚函数表)。
    但是它们的实际函数都是访问子类的实际虚函数。
     
  • virtual继承:
    进行隐式转换或进行显式转换均可时(代码中简写为隐式强转),指针指向子类时指向地址均需要偏移,根据指针的类型对虚函数进行地址偏移(访问指针类型对象的虚函数表)。
    必须进行显式转换时指针指向地址均不变,按照强制转换前的类型对虚函数进行地址偏移(访问原来类型的虚函数表)。
    但是它们的实际函数都是访问子类的实际虚函数。

virtual继承与非virtual继承的差别其实仅在于不需要显式转换时的最左父类指针是否偏移。这与当时的虚函数表布局方式有关。
virtual继承将新的virtual方法都写在自身vftable中; 而非virtual继承则将新的virtual方法更新到最左父类的vftable中。

测试代码:

非virtual继承: 

  1. #include <iostream>
  2.  
  3. class A
  4. {
  5. public:
  6.         void fun() { std::cout << "A::fun()" << std::endl; }
  7.         virtual void vfun() { std::cout << "A::vfun()" << std::endl; }
  8.         virtual void vfun1() { std::cout << "A::vfun1()" << std::endl; }
  9. };
  10.  
  11. class B
  12. {
  13. public:
  14.         virtual void vfun2() { std::cout << "B::vfun2()" << std::endl; }
  15. };
  16.  
  17. class C
  18. {
  19. public:
  20.         virtual void vfun3() { std::cout << "C::vfun3()" << std::endl; }
  21. };
  22.  
  23. class D: public A, public B, public C
  24. {
  25. public:
  26.         virtual void vfun2() { std::cout << "D::vfun2()" << std::endl; }
  27.         virtual void vfun3() { std::cout << "D::vfun3()" << std::endl; }
  28.         virtual void vfun() { std::cout << "D::vfun()" << std::endl; }
  29. };
  30.  
  31. typedef void (*Fun) (void);
  32.  
  33. void TestCast(D* d)
  34. {
  35.         std::cout << "d: \t\t\t" << d << std::endl << std::endl;
  36.  
  37.         A* pA = d;
  38.         std::cout << "A* pA = d: \t\t" << pA << std::endl;
  39.         std::cout << "pA -> fun(): \t\t"; pA->fun();
  40.         std::cout << "pA -> vfun(): \t\t"; pA->vfun();
  41.         std::cout << "pA -> vfun1(): \t\t"; pA->vfun1();
  42.         std::cout << "隐式强转:最左父类的指针指向地址不变,指向函数按指针类型对象的虚表结构偏移,但虚表依然是原对象的虚表" << std::endl;
  43.         std::cout << std::endl;
  44.        
  45.         C* pC = (C*) pA;
  46.         std::cout << "C* pC = (C*) pA: \t" << pC << std::endl;
  47.         std::cout << "pC -> vfun3(): \t\t"; pC->vfun3();
  48.         std::cout << "显式强转:指针指向地址不变,指向函数按强转前的类型的虚表结构偏移,但虚表依然是原对象的虚表" << std::endl;
  49.         std::cout << std::endl;
  50.  
  51.         B* pB = d;
  52.         std::cout << "B* pB = d: \t\t" << pB << std::endl;
  53.         std::cout << "pB -> vfun2(): \t\t"; pB->vfun2();
  54.         std::cout << "隐式强转:非最左父类的指针指向地址变化,指向函数按指针类型对象的虚表结构偏移,但虚表依然是原对象的虚表" << std::endl;
  55.         std::cout << std::endl;
  56.  
  57.         pA = (A*) pB;
  58.         std::cout << "A* pA = (A*) pB: \t" << pA << std::endl;
  59.         std::cout << "pA -> fun(): \t\t"; pA->fun();
  60.         std::cout << "pA -> vfun(): \t\t"; pA->vfun();
  61.         std::cout << "显式强转:指针指向地址不变,指向函数按强转前的类型的虚表结构偏移,但虚表依然是原对象的虚表" << std::endl;
  62.         //pA->vfun1();    //        B类中只有一个virtual
  63.         std::cout << std::endl;
  64. }
  65.  
  66. void TestCast(A* a)
  67. {
  68.         std::cout << "a: \t\t\t" << a << std::endl << std::endl;
  69.  
  70.         D* d = (D*) a;
  71.         std::cout << "D* d = a: \t\t" << d << std::endl;
  72.         d->fun();
  73.         d->vfun();
  74.         d->vfun1();
  75.         //d->vfun2();   // A类中没有vfun2
  76.         //d->vfun3();   // A类中没有vfun3
  77.         std::cout << std::endl;
  78.  
  79.         B* b = d;
  80.         std::cout << "B* b = d: \t\t" << b << std::endl;
  81.         //b->vfun2();   // A类中没有vfun2
  82.         std::cout << std::endl;
  83.  
  84.         b = (B*) a;
  85.         std::cout << "B* b = (B*) a:\t\t" << b << std::endl;
  86.         b->vfun2();          //   A类vtable的第一个项是vfun
  87.         std::cout << std::endl;
  88. }
  89.  
  90. void main(void)
  91. {
  92.         D d;
  93.         TestCast(&d);
  94.  
  95.         A a;
  96.         TestCast(&a);
  97.  
  98.         system("pause");
  99. }
virtual继承:
  1. #include <iostream>
  2.  
  3. class A
  4. {
  5. public:
  6.         void fun() { std::cout << "A::fun()" << std::endl; }
  7.         virtual void vfun() { std::cout << "A::vfun()" << std::endl; }
  8.         virtual void vfun1() { std::cout << "A::vfun1()" << std::endl; }
  9. };
  10.  
  11. class B
  12. {
  13. public:
  14.         virtual void vfun2() { std::cout << "B::vfun2()" << std::endl; }
  15. };
  16.  
  17. class C
  18. {
  19. public:
  20.         virtual void vfun3() { std::cout << "C::vfun3()" << std::endl; }
  21. };
  22.  
  23. class D: virtual public A, virtual public B, virtual public C
  24. {
  25. public:
  26.         virtual void vfun3() { std::cout << "D::vfun3()" << std::endl; }
  27.         virtual void vfun() { std::cout << "D::vfun()" << std::endl; }
  28. };
  29.  
  30. void TestCast(D* d)
  31. {
  32.         std::cout << "d: \t\t\t" << d << std::endl << std::endl;
  33.  
  34.         A* pA = d;
  35.         std::cout << "A* pA = d: \t\t" << pA << std::endl;
  36.         std::cout << "pA -> fun(): \t\t"; pA->fun();
  37.         std::cout << "pA -> vfun(): \t\t"; pA->vfun();
  38.         std::cout << "pA -> vfun1(): \t\t"; pA->vfun1();
  39.         std::cout << "隐式强转:指针指向地址变化,指向函数按指针类型对象的虚表结构偏移,但虚表依然是原对象的虚表" << std::endl;
  40.         std::cout << std::endl;
  41.  
  42.         C* pC = (C*) pA;
  43.         std::cout << "C* pC = (C*) pA: \t" << pC << std::endl;
  44.         std::cout << "pC -> vfun3(): \t\t"; pC->vfun3();
  45.         std::cout << "显式强转:指针指向地址不变,指向函数按强转前的类型的虚表结构偏移,但虚表依然是原对象的虚表" << std::endl;
  46.         std::cout << std::endl;
  47.  
  48.         B* pB = d;
  49.         std::cout << "B* pB = d: \t\t" << pB << std::endl;
  50.         std::cout << "pB -> vfun2(): \t\t"; pB->vfun2();
  51.         std::cout << "隐式强转:指针指向地址变化,指向函数按指针类型对象的虚表结构偏移,但虚表依然是原对象的虚表" << std::endl;
  52.         std::cout << std::endl;
  53.  
  54.         pA = (A*) pB;
  55.         std::cout << "A* pA = (A*) pB: \t" << pA << std::endl;
  56.         std::cout << "pA -> fun(): \t\t"; pA->fun();
  57.         std::cout << "pA -> vfun(): \t\t"; pA->vfun();
  58.         std::cout << "显式强转:指针指向地址不变,指向函数按强转前的类型的虚表结构偏移,但虚表依然是原对象的虚表" << std::endl;
  59.         //pA->vfun1();    //        B类中只有一个virtual
  60.         std::cout << std::endl;
  61. }
  62.  
  63. void TestCast(A* a)
  64. {
  65.         std::cout << "a: \t\t\t" << a << std::endl << std::endl;
  66.  
  67.         //D* d = (D*) a;        //      不能从虚拟基类转换成子类
  68.  
  69.         B* b = (B*) a;
  70.         std::cout << "B* b = (B*) a:\t\t" << b << std::endl;
  71.         b->vfun2();          //   A类vtable的第一个项是vfun
  72.         std::cout << std::endl;
  73. }
  74.  
  75. void main(void)
  76. {
  77.         D d;
  78.         TestCast(&d);
  79.  
  80.         A a;
  81.         TestCast(&a);
  82.  
  83.         system("pause");
  84. }

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter