【问题标题】:Can a base class have a member that is an instance of a derived class?基类可以有一个派生类实例的成员吗?
【发布时间】:2013-09-16 03:53:51
【问题描述】:

我可以有一个基类,其成员是派生类的实例吗?我应该如何前向声明或包含派生类定义?还是我应该这样做的另一种方式?

// base.h

class DerivedClass;  // Is forward declaration sufficient?

class Base {
 public:
  virtual ~Base();
  virtual void DoStuff() = 0;
  void DoSomethingWithD() {
    d_.Foo();
  }
 protected:
  DerivedClass d_;
};

// derived.h

#include "base.h"

class Derived : public Base {
 public:
  Derived();
  void DoStuff();
  void Foo();
 private:
  Derived(const Derived&);
  void operator=(const Derived&);
};

// other_derived.h

#include "base.h"

class OtherDerived : public Base {
 public:
  OtherDerived();
  void DoStuff();
 private:
  OtherDerived(const OtherDerived&);
  void operator=(const OtherDerived&);
};

【问题讨论】:

  • 您可以使用 CRTP en.wikipedia.org/wiki/Curiously_recurring_template_pattern 并将派生类的实例作为基类中的指针来实现此目的。
  • 不,你不能。即使使用 CRTP。 Base 的大小取决于Derived 的大小,这取决于Base 的大小。但是,您可以存储派生类的指针或引用。
  • @DyP 啊。我不需要会员。我可以得到一个指针。所以,那么前向声明就足够了。谢谢。
  • @Dyp 你错过了我评论的第二部分。我提到 CRTP 有点过分了 ;)
  • @Troy 嗯....哎呀! ;)

标签: c++ inheritance c++11


【解决方案1】:

这对你有用,请参阅 cmets 的更改:

#include <memory>

class Derived;

class Base {
 public:
  virtual ~Base();
  virtual void DoStuff() = 0;
  void DoSomethingWithD();      // no longer defined in-line
 protected:
  std::unique_ptr<Derived> d_;  // storing as a pointer as Derived is still incomplete
};

class Derived : public Base {
 public:
  Derived();
  void DoStuff();
  void Foo();
 private:
  Derived(const Derived&);
  void operator=(const Derived&);
};

class OtherDerived : public Base {
 public:
  OtherDerived();
  void DoStuff();
 private:
  OtherDerived(const OtherDerived&);
  void operator=(const OtherDerived&);
};

// definition moved down here where Derived is a complete type
void Base::DoSomethingWithD() { 
  d_->Foo();
}

【讨论】:

  • “将指针存储为类型仍然不完整”我认为,严格来说,这并不完全正确。 [basic.types]/5 "已声明但未定义的类,或未知大小或不完整元素类型的数组,是未完全定义的对象类型。未完全定义的对象类型和 void 类型是不完整类型。”尽管Derived 不完整,但unique_ptr&lt;Derived&gt; 是完整的,因为否则您不能将其用作成员:[class.mem]/9 "非静态数据成员不应具有不完整的类型。"也就是说,您确实需要一个外线(ctor 和)dtor。
  • unique_ptr 被允许持有指向不完整类型的指针。它只需要在您调用 unique_ptr 上的成员函数时完成(例如,它的析构函数)。因为Derived 的定义在Base 的定义之后是可见的,所以这不是问题。
猜你喜欢
  • 1970-01-01
  • 2012-10-29
  • 1970-01-01
  • 2023-03-19
  • 2021-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-15
相关资源
最近更新 更多