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++基类包含派生类的实例的主要内容,如果未能解决你的问题,请参考以下文章