C ++ 03:向几个派生类添加字段

时间:2014-12-07 23:48:26

标签: c++ oop inheritance derived-class

我有几个派生类(例如DerivedX,其中x是派生类号),它们在字段和成员函数中有所不同。 比我想用一组属性扩展每个派生类(可以组织为一个字段Extension ex),保留每个DerivedX类。后者意味着我们可以创建不包含属性DerivedX的“清晰”Extension ex对象。

派生对象是在某些代码位置创建的(例如,在函数main()中),如果它们具有扩展功能,则应使用此功能(get,set,其他方法从{{ 1}})。

第一个想法是将这个新属性添加到每个派生类,为每个派生类形成新类(main())。但我觉得代码会变得笨重,看起来,这种做法很糟糕:

ExtendedX

在这种情况下,每个班级都会重复要求的功能。这是一种高度弃用的做法。

另一个(第二个)想法是声明“类扩展”,它将包含所考虑的属性(示例中为class Base { protected: int b; ... } class Derived1: public Base { protected: int d1; ... }; class Derived2: public Base { protected: int d2; ... } ...X classes defined class Extended1: public Derived1 { protected: Extension ex; public: int getExProperty1(){return ex.getProperty1();} // the realization could differ: we could also return copy of Extension object, pointer, set every field separately or the whole Extension object } class Extended2: public Derived2 { protected: Extension ex; public: int getExProperty1(){return ex.getProperty1();} // the realization could differ: we could also return copy of Extension object, pointer, set every field separately or the whole Extension object } ...X classes defined )并按需创建其对象以及类"Extension ex"的对象,当我们需要DerivedX个对象来拥有这个属性时。

第三个想法是将指向DerivedX的指针作为字段包含在Base类中,并在我们不想使用扩展功能时将其初始化为NULL。但是,我们如何从Extension

调用Extension类的方法

扩展功能在未来也可能有所不同(派生类根据所解决的问题类型进行扩展),这就是为什么第二个和第三个想法也比第一个更好。

是否有任何好的解决方案可以为多个派生类添加属性和功能包?


EDIT1: 我试图通过CRTP实现mixin,正如Deduplicator所建议的那样。 但是,代码失败了:

main()

代码:

«class Base» has no member named «getProperty1»
«class Base» has no member named «setProperty1»

更改

#include <iostream>
using namespace std;

class Base {
   int a;
public:
   virtual ~Base(){}
};

class Derived1: public Base
{
public:
   virtual ~Derived1(){}
};

template <class T> class Extension: public T
{
   int prop1;
 public:
   void setProperty1(int _p){prop1=_p;}
   int getProperty1(){return prop1;}
};

int main()
{
Base* der = new Derived1();
Base* e = new Extension<Derived1>();
e->setProperty1(10);
cout<< e->getProperty1();
delete der;
delete e;
return 0;
}

e->

使代码正常工作。

在这种情况下如何正确使用static_cast<Extension<Derived1> *>(e)-> 类对象?

3 个答案:

答案 0 :(得分:4)

使用CRTP:

// Classes implementing additions

template<class T> class Extended : public T /*, potentially additional bases */ {
    // Common extension here.
}

答案 1 :(得分:2)

如果您可以重新定义各种Derived类但无法更改Base的定义,则另一个选项是将Extension推入它们之间的类层次结构中{{1 }}:

Base

这样,class Base { // ... }; class Extension: public Base { // ... }; class Derived1: public Extension { // ... }; class Derived2: public Extension { // ... }; 中不需要新API的任何内容都可以继续使用Extension,而需要新API的部分可以使用Base*(或{{ 1}})而不是。

这假定Extension*需要访问dynamic_cast<Extension>(baseptr)。如果没有,那么您可以将Extension实现为mixin:

Base

答案 2 :(得分:1)

组合或继承?

  

当我们需要Derived对象拥有此属性时。

这听起来好像一个物体及其扩展属性有一个&#34; has-a &#34;而不是&#34; 是-a &#34;关系。这将表明构成而不是继承作为解决方案。

  

&#34;按需提供&#34; ,&#34;如果我们不想要&#34; ...

这表明可选择的关系。听起来好像你在运行时和每个对象决定是否需要扩展。这加强了对组合而不是继承的偏好。

要实现这种继承需要多态的行为,并且每次需要使用对象时都必须使用指针/引用。

  

扩展功能在未来也可能有所不同(派生   课程根据问题的类型进行扩展   解决),

将来,衍生出来还有进一步的推导吗?如果是,这种进一步的推导将如何与扩展相关?如果你说进一步的推导与扩展无关,那么组合应该是最终的选择。

现在更喜欢2和3中的哪一个?

考虑上面的所有论点,第三个选项对于您当前对共同扩展的需求以及未来需求都非常有趣。

以下是一般概念:

class Base {
   ...
protected:
   Extension *ex;
   void setExtension(Extension *e);   // to be called by ctor or the derived.
public:
   bool isExtended() { return ex!=nullptr; } 
   int getExProperty1(){ if (isExtend()) return ex->getProperty1();} // common member functions 
};

但为了保持未来演变的可扩展性,Extension应该将其成员函数定义为虚拟。然后,一些派生类可以使用Extension的派生:

class MyDerivedExtension : public Extension {  // specially for Derived1 extensions
protected:
    string myspecificproperty;   // specific for Derived1
public:  
    int getPropery1 () { /* calculate it differently than for basic Extension */ }
    string getProperty2 () { /*...*/ }  // specific to Derived1
};

class Derived1: public Base
{
...
protected:  
   void setExtension(MyDerivedExtension *e) { Base::setExtension(e); }  // to be called by ctor.     
public: 
   string getExProperty2(){ if (isExtend()) return ex->getProperty2();} // non common member         
};