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

Posted

技术标签:

【中文标题】c++基类包含派生类的实例【英文标题】:c++ base class contain instance of a derived class 【发布时间】:2013-01-11 20:59: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


谢谢

【问题讨论】:

真的,如果你仔细想想,这有点傻。 A 将具有一定的大小(包括嵌入的 B),例如 N 字节。但是 B 至少会一样大,因为它包含 A 所做的所有字段,所以 A 需要更大才能容纳,这意味着 B 需要更大,.... . 另外,A 包含的B 必须包含一个A 作为它的基础对象,并且A 必须包含一个B,它必须包含一个A, ....跨度> 【参考方案1】:

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

namespace advanced_cpp_oop

  class B;

  class A
  
    B* b;
  ;

  class B : public A
  
  ;

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

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

另一方面,从设计的角度来看,这并没有真正的意义,因为父类不应该依赖于子类。

【讨论】:

是的,具体怎么做。【参考方案2】:

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

  class B;

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

  class B : public A
  
  ;

这很愚蠢,您可能应该重新考虑您的设计。

【讨论】:

Coplein 的“Envelope/Letter”和相关的成语浮现在脑海中——有时这样做是有意义的......【参考方案3】:

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

如果您牢记这一点,就很容易理解为什么以下内容可能不起作用:

class Base 
   Derived d;
;
class Derived : Base ;

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

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

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

【讨论】:

【参考方案4】:

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

【讨论】:

以上是关于c++基类包含派生类的实例的主要内容,如果未能解决你的问题,请参考以下文章

C++ 派生模板类:访问实例的受保护成员

派生类的 C++ 构造函数,其中基类包含类成员

C++ 包含两个派生自同一个基类的类

在 C++ 中将指向基类的指针传递给派生类的成员函数

在 C++ 中,为啥只包含联合及其基类实例的派生类占用的内存比联合的大小还要多?

关于C++基类与派生类