我想知道是否有人可以向我解释我如何能够实现类似的内容:
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
{
}
由于
答案 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)
B b = new B(...);
语句遍布Java代码),即使它没有看起来像。您的原始C ++代码不起作用(即使添加了B类的前向声明),因为编译器不知道B对象有多大,因此不知道包含它的A对象有多大。另一方面,所有指针都具有相同的大小(无论指向类型),因此当您使用指向A类中B对象的指针替换B对象时,编译器不会出现此类问题。