我有几个派生类(例如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)->
类对象?
答案 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
};