0
#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中。这可以在编译时确定。在上述情况下,如果我们将 foo 与 D 的对象一起传递,则只有在编译时我们才能计算 D 的 A 部分的偏移量。

4

4 回答 4

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 的 A 部分的偏移量。

这是一种误解。现在编写的 foo 函数除了 A * 之外没有关于 ptr 类型的编译类型信息,即使您传递 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),因此这可能不是你想要的。

虚函数

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

class A
{
   int a;
   int b;

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

如果您不接受虚函数,则其编译时机制是模板,如上所述。

于 2008-12-19T09:57:34.207 回答
3

使用演员static_cast表 - 此处需要转换层次结构。

main()
{
  D obj;
  foo(static_cast<B*>(&obj));
}
于 2008-12-19T09:52:41.753 回答
1

首先,obj没有一个名为B的成员。它继承自B,也就是说它继承了B的所有成员作为自己的成员。

您可以致电:

foo(static_cast<B*>(&obj));
让它工作。

于 2008-12-19T09:54:08.893 回答
1

我不认为 static_cast 会起作用。

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

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

于 2008-12-19T10:05:29.527 回答