我想知道,如果有人可以给我解释一下我如何能够实现类似这样:
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 B
中class A
,因为编译器还不知道任何东西(特别是没有大小),这是不可能的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 ++中的第一个定义意味着对象基地内部含有(未用参考)的派生类型的一个对象。 同时,导出通过继承的手段包含类型的碱的子对象。
这意味着,派生包含包含派生含碱...什么是基地或派生大小的基地?
在引用语义,或在C ++中,如果你使用指针语言,那是没有问题的。 基础对象包含衍生参照/指针 。 派生包含通过继承方式基类子对象。 基地的大小是公知的:所有其他字段加一参考/指针的大小。 源性的大小无论是基地的规模加上添加任何额外的成员。
安德烈亚斯打我正确的答案,但我只想补充一点,Java代码的工作,只是因为Java对象是隐式指针举行(因此B b = new B(...);
在整个Java代码洒语句),即使它看起来并不像它。 你原来的C ++代码不能正常工作(甚至B级的前向声明加入),因为编译器不知道B的对象有多大,因此不知道有多大的包含这将是一个对象。 在另一方面,所有的指针具有相同的尺寸(无论指向的类型),因此编译器没有这样的问题,当您的指针B的对象类A.替换B对象