C ++“在多个基类上处理虚函数”

时间:2012-08-27 17:59:54

标签: c++ polymorphism multiple-inheritance

我需要从两个不同的基类 CBaseA CBaseB 派生一个子类 CDerived

另外,我需要在派生类上调用父对象的虚函数。由于我想稍后在一个向量中管理不同类型的对象(这不是这个最小代码示例的一部分),我需要从基类指针调用虚函数到派生类对象:

#include <iostream>
#include <stdlib.h>

class CBaseA
{
  public:
    virtual void FuncA(){ std::cout << "CBaseA::FuncA()" << std::endl; };
};

class CBaseB
{
  public:
    virtual void FuncB(){ std::cout << "CBaseB::FuncB()" << std::endl; };
};

class CDerived : public CBaseB, public CBaseA
{};

int main( int argc, char* argv[] )
{
  // An object of the derived type:
  CDerived oDerived;

  // A base class pointer to the object, as it could later
  // be stored in a general vector:
  CBaseA* pAHandle = reinterpret_cast<CBaseA*>( &oDerived );

  // Calling method A:
  pAHandle->FuncA();

  return 0; 
}

问题:但是在我的计算机上运行时,会调用 FuncB()而不是 FuncA()。如果我“翻转”父类的deklarations,即

,我得到了正确的结果
class CDerived : public CBaseA, public CBaseB

但这并不能解决我的问题,因为我无法确定将调用哪个函数。

所以我的问题是: 我做错了什么以及处理此类问题的正确方法是什么?

(顺便说一句,我使用的是g ++ 4.6.2)

2 个答案:

答案 0 :(得分:7)

CBaseA* pAHandle = reinterpret_cast<CBaseA*>( &oDerived );

不要使用reinterpret_cast来执行到基类的转换。不需要演员阵容;转换是隐含的:

CBaseA* pAHandle = &oDerived;

要转换为派生类,如果已知对象属于目标类型,则使用static_cast;如果不知道对象,则使用dynamic_cast

您对reinterpret_cast的使用会产生未定义的行为,因此您会看到“奇怪”的行为。 reinterpret_cast的正确用法很少,而且没有一个涉及类层次结构中的转换。

答案 1 :(得分:2)

可以帮助您了解会发生什么的常见实施。

记忆中的CBaseA看起来像这样

+---------+
| __vptrA |
+---------+

内存中的CBaseB看起来像这样

+---------+
| __vptrB |
+---------+

CDerived看起来像这样:

             +---------+
&oDerived->  | __vptrB |
             | __vptrA |
             +---------+

如果您只是将&amp; oDerived分配给CBaseA *,编译器会放置代码以添加偏移量,以便您拥有

             +---------+
&oDerived--->| __vptrB |
pAHandle---->| __vptrA |
             +---------+

在执行期间,程序在__vptrA中找到指向虚函数的指针。如果你将static_cast或dynamic_cast pAHandle返回给CDerived(甚至是动态广播pAHandle到CBaseA),编译器会把代码减去偏移量,以便结果指向对象的开头(dynamic_cast会找到有关多少的信息)在vtable中减去指向虚函数的指针。)

当你重新解释并发布作为CBaseA *时,编译器不会把这样的代码调整指针,你得到

                       +---------+
pAHandle, &oDerived--->| __vptrB |
                       | __vptrA |
                       +---------+

在执行过程中,程序查看了__vptrB的A虚函数,找到了B虚函数。