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

c++ base class contain instance of a derived class

本文关键字:实例 派生 基类 包含 c++      更新时间:2023-10-16

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

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
{
}

谢谢

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

namespace advanced_cpp_oop
{
  class B;
  class A
  {
    B* b;
  };
  class B : public A
  {
  };
}

在你的c++代码中,你正在class A中创建class B的实例,这是不可能的,因为编译器还不知道class B的任何东西(特别是不知道大小)。

从我的答案的代码,你需要动态分配class B的实例,并将其分配给b指针在你的代码的其他地方。

从设计的角度来看,这是没有意义的,因为父类不应该依赖于子类。

您必须使用某种类型的指针(例如unique_ptr)和前向声明:

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

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

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

如果你记住这一点,就很容易理解为什么下面的代码不可能工作:

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

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

这意味着派生类包含一个基类,而基类又包含一个派生类包含一个基类…Base或Derived的大小是多少?

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

Andreas比我先给出了正确的答案,但我要补充的是,Java代码之所以有效,只是因为Java对象是由指针隐式保存的(因此在Java代码中散布着B b = new B(...);语句),即使它看起来不像。您的原始c++代码无法工作(即使添加了类B的前向声明),因为编译器不知道B对象有多大,因此不知道包含它的a对象将有多大。另一方面,所有指针都有相同的大小(不管指向类型是什么),所以当您用指向类a中的B对象的指针替换B对象时,编译器不会出现这样的问题。