c ++基类包含派生类的实例

时间:2013-01-11 20:59:17

标签: c++ oop class inheritance

我想知道是否有人可以向我解释我如何能够实现类似的内容:

namespace advanced_cpp_oop
{
  class A
  {
    B b;
  };

  class B : public A
  {
  };
}

int main()
{
}

基类的实例可以包含派生类的实例吗?编译上述代码时,会生成以下错误:

g++ advanced_cpp_oop.cpp 
advanced_cpp_oop.cpp:8:5: error: ‘B’ does not name a type

编译的(几乎)等效的Java代码是:

public class AdvancedCppOop
{
  public static void main(String[] args)
  {
    A a;
  }
}

class A
{
  B b;
}

class B extends A
{
}

由于

4 个答案:

答案 0 :(得分:5)

你需要一个指针和一个前向声明:

namespace advanced_cpp_oop
{
  class B;

  class A
  {
    B* b;
  };

  class B : public A
  {
  };
}

在您的C ++代码中,您正在class B内创建class A的实例,这是不可能的,因为编译器还不知道{{1}的任何内容(特别是大小) }。

使用我的答案中的代码,您需要动态分配class B的实例,并将其分配给代码中其他位置的class B指针。

从侧面说明,从设计的角度来看,这并不合理,因为父类不应该依赖于子类。

答案 1 :(得分:4)

您必须使用某种类型的指针(例如unique_ptr)和前向声明来执行此操作:

  class B;

  class A
  {
    std::unique_ptr<B> b;
  };

  class B : public A
  {
  };

这很愚蠢,你应该重新考虑你的设计。

答案 2 :(得分:3)

C ++和Java之间有一个非常重要的区别。 C ++是一种具有值语义的语言,而Java是一种具有引用语义的语言。在Java中,您创建的是除基本类型之外的任何变量,您不是要创建该类型的对象,而是创建对此类对象的引用。相反,在C ++中,相同的构造指的是一个实际的对象。

如果你记住这一点,很容易理解为什么以下内容无法发挥作用:

class Base {
   Derived d;
};
class Derived : Base {};

C ++中的第一个定义意味着对象Base在内部(不是通过引用)包含Derived类型的对象。同时,Derived通过继承包含Base类型的子对象。

这意味着Derived包含一个Base,其中包含一个包含Base的Derived ... Base或Derived的大小是多少?

在具有引用语义的语言中,或者在使用指针的C ++中,这不是问题。 Base对象包含Derived的引用/指针。 Derived通过继承包含Base子对象。 Base的大小众所周知:所有其他字段加上引用/指针的大小。 Derived的大小是Base的大小加上添加的任何额外成员。

答案 3 :(得分:2)

Andreas打败了我正确的答案,但我只想补充一点,Java代码的工作原理只是因为Java对象是由指针隐式保存的(因此B b = new B(...);语句遍布Java代码),即使它没有看起来像。您的原始C ++代码不起作用(即使添加了B类的前向声明),因为编译器不知道B对象有多大,因此不知道包含它的A对象有多大。另一方面,所有指针都具有相同的大小(无论指向类型),因此当您使用指向A类中B对象的指针替换B对象时,编译器不会出现此类问题。