1

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

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

谢谢

4

4 回答 4

5

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

namespace advanced_cpp_oop
{
  class B;

  class A
  {
    B* b;
  };

  class B : public A
  {
  };
}

在您的 C++ 代码中,您正在创建class Binside的一个实例class A,这是不可能的,因为编译器还不知道class B.

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

附带说明一下,从设计的角度来看,这并没有真正的意义,因为父类不应该依赖于子类。

于 2013-01-11T21:04:04.660 回答
4

您必须使用某种类型的指针(例如 unique_ptr)和前向声明来执行此操作:

  class B;

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

  class B : public A
  {
  };

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

于 2013-01-11T21:06:32.107 回答
3

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

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

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

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

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

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

于 2013-01-11T22:21:20.770 回答
2

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

于 2013-01-11T21:09:18.940 回答