多重继承

时间:2008-12-19 09:44:15

标签: c++ inheritance multiple-inheritance

#include<iostream>
using namespace std;

class A

{
   int a;
   int b;
   public:
   void eat()
   {
      cout<<"A::eat()"<<endl;
   }
};

class B: public A
{
   public:
   void eat()
   {

      cout<<"B::eat()"<<endl;

   }

};

class C: public A
{

   public:
   void eat()

   {

      cout<<"C::eat()"<<endl;

   }

};

class D: public B, C
{

};

int foo(A *ptr)
{

ptr->eat();

}
main()
{

D obj;
foo(&(obj.B)); //error. How do i call with D's B part.

}

上面的foo调用是编译时错误。 我想用obj的B部分调用foo而不使用虚拟继承。我怎么做。

此外,在虚拟继承的情况下,为什么需要将偏移信息存储在vtable中。这可以在编译时自己确定。在上面的例子中,如果我们用D的对象传递foo,在编译时我们只能计算D的A部分的偏移量。

4 个答案:

答案 0 :(得分:6)

继承两次

使用双重继承你有一个歧义 - 编译器无法知道你想要使用哪两个A基。如果你想拥有两个A基(有时你可能想要这样做),你可以通过转换为B或C来选择它们。这里默认转换最合适的是static_cast(最弱的可用) ,但它并不是真正需要的(它仍然比你的情况需要更强),因为你没有强制转换为派生类型。自定义safe_cast模板应该可以胜任:

/// cast using implicit conversions only
template <class To,class From>
inline To safe_cast( const From &from ) {return from;}

main()
{

  D obj;
  foo(safe_cast<B *>(&obj)); //error. How do i call with D's B part.

}

编译时间类型 - 使用模板

  

另外,在虚拟继承的情况下,   为什么偏移信息需要   存储在vtable中。这可以   在编译时确定。   在上面的例子中,如果我们传递foo   D的对象,只在编译时我们   可以计算D'的偏移量   一部分。

这是一种误解。现在编写的foo函数没有关于ptr类型的编译类型信息,除非它是A *,即使你传递B *或C *。如果您希望foo能够根据传递编译时间的类型进行操作,则需要使用模板:

template <class TypeDerivedFromA>
int foo(TypeDerivedFromA *ptr)
{
  ptr->eat();
}

虚拟继承

您的问题提到了虚拟继承。如果要使用虚拟继承,则需要指定:

class B: public virtual A ...

class C: public virtual A ...

这样代码就可以编译了,但是使用这个解决方案,你无法在B :: A或C :: A(只有一个A)之间进行选择,因此这可能与你无关。 / p>

虚拟功能

此外,您的问题似乎混淆了两个不同的概念,虚拟继承(这意味着在两个中间基类之间共享一个基类)和虚函数(这意味着允许通过基类指针调用派生类函数)。如果你想使用A指针调用B :: eat,你可以使用虚函数执行此操作而不使用虚拟继承(实际上虚拟继承会阻止你这样做,如上所述):

class A
{
   int a;
   int b;

   public:
   virtual void eat()
   {
      cout<<"A::eat()"<<endl;
   }
};

如果你不接受虚函数,那么编译时机制就是模板,如上所述。

答案 1 :(得分:3)

使用强制转换 - 此处需要static_cast来强制转换层次结构。

main()
{
  D obj;
  foo(static_cast<B*>(&obj));
}

答案 2 :(得分:1)

首先,obj没有名为B的成员。它继承自B,这意味着它继承了B的所有成员。

您可以致电:

foo(static_cast<B*>(&obj));
让它发挥作用。

答案 3 :(得分:1)

我不认为static_cast会起作用。

当你使用foo函数时,所有编译器都知道你有一个指向A的指针,无论你传递给参数的类型是什么。

如果你不使用虚拟继承,那么我认为没有办法从指向A的指针调用B函数。

相关问题