0

这是一个好的模式吗?

BaseClass {
protected:
  Data m_data;
public:
  Interesting public_method() {
    //returns something interesting about m_data
    //what exactly depends on what the subclass put into m_data
  }
}

DerivedClass {
public:
  DerivedClass() { //properly populate m_data }
}

这样做的缺点是事情太“松散”并且没有在编译时强制执行,因为子类程序员只是被告知做某事,而不是真的被迫去做,所以我想知道这是否被经验丰富的 c++ 编码人员认为是好的做法。

有什么好的出路或更好的方法吗?

如果只有超类构造函数可以在子类构造函数完成其工作后被强制调用。然后超类构造函数中可以包含所需的参数

c++ 不允许这样做:(

4

5 回答 5

1

这不是一种模式,而是一种反模式。经验法则:受保护的变量不好。继承的行为(从一般的具体类继承)是不好的。当然,有时可能有理由忽略其中任何一个,但如果不说出你真正想要做什么,就很难说。

于 2013-02-08T20:52:13.357 回答
1

在我看来,永远不应该使用受保护的变量。我更喜欢使用带有受保护方法的私有变量。这样,如果您想使用多态对象,您可以覆盖您的方法并避免“坏意外”。如果你的类是final,当然你可以直接使用受保护的变量。

于 2013-02-08T20:54:08.263 回答
1

对我来说,这听起来不太对劲。尽管派生类调用基类并非闻所未闻,但更常见的是派生类将覆盖(虚拟)public_method以提供该信息。

或者,按照建议,使用工厂函数。或者一个静态的“构造函数”成员函数,所以不是调用 new,而是调用一个调用newspecial function to make set the data.

所有可能的解决方案。

于 2013-02-08T20:56:13.937 回答
1

如果只有超类构造函数可以在子类构造函数完成其工作后被强制调用。然后超类构造函数中可以包含所需的参数。

ctor -initializer-list非常强大。虽然您只能使用表达式,但这些表达式可以包含函数调用。实际上,您可以在构造函数主体中执行的任何操作都可以从初始化列表中实现。

当然,你必须尊重构造顺序,所以你不能在初始化之前调用基类上的成员函数。但是您可以在初始化成员时访问基类。

class BaseClass
{
  Data m_data;
protected:
  BaseClass( Data&& data ) m_data(data) {}
public:
  Interesting public_method() {
    //returns something interesting about m_data
    //what exactly depends on what the subclass put into m_data
  }
};

class DerivedClass : public BaseClass
{
  static Data make_arg_into_data( const T& arg ) { /* calculate and return the right value for m_data */ }
  static Interesting make_arg_into_member_init( BaseClass* pThis, const T& arg ) { return pThis->public_method(); }
  V m_member;
public:
  DerivedClass( T arg ) BaseClass(make_arg_into_data(arg)), m_member(make_arg_into_member_init(this, arg)) {  }
};
于 2013-02-08T21:02:05.423 回答
0

听起来你可以使用工厂:

BaseClass {
private:
  Data m_data;
public:
  void setData(const Data& data) { m_data = data; }
  virtual Data generateData() = 0;
};

struct Factory
{
   template<class T>
   static BaseClass* getInstance()
   {
       BaseClass* t = new T;
       t->setData(t->generateData());
       return t;
   }
};

并将其称为

BaseClass* p = Factory::getInstance<Derived>();

如您所见,非抽象派生类被迫调用generateData,因此它们必须生成有效的Data.

我只使用原始指针以方便编写,不要:)

于 2013-02-08T20:51:15.420 回答