问题
I have the following problem. I have a base class and several classes inheriting from it. All those classes are sharing a very similar interface and will most probably not be required to overload most of the shared methods.
However, all of them are using different member objects that are derived from each other and share a very similar interface too.
class BaseClass
{
protected:
Com* com;
public:
void setReady()
{
com->setReady();
}
}
class DerivedClass : BaseClass
{
protected:
DerivedCom* com;
}
class Derived2Class : BaseClass
{
protected:
Derived2Com* com;
}
How can I enable DerivedClass
to have setReady()
run its version of com
instead of the one inherited from BaseClass
?
回答1:
Construct your instances with different implementations of Com. (Assuming DerivedCom implements Com)
class BaseClass
{
protected:
Com* com;
public:
BaseClass(Com* c = new Com) : com(c)
{}
void setReady()
{
com->setReady();
}
}
class DerivedClass : BaseClass
{
public:
DerivedClass() : BaseClass(new DerivedCom)
{}
}
class Derived2Class : BaseClass
{
public:
Derived2Class() : BaseClass(new Derived2Com)
{}
}
回答2:
A simple solution is to introduce a getCom()
protected virtual function, that returns a Com*
or Com&
:
virtual Com* getCom()
{ return this->com; }
The child classes can override it and return their own Com-derived instance. Your setReady()
function can then be implemented as:
void setReady()
{
getCom()->setReady();
}
Your com
member can then be made private
, btw.
The drawback with this solution is that you'll have multiple Com
-derived instances in the child classes.
回答3:
Maybe a class template might help you:
class BaseClass
{
protected:
Com* com;
public:
virtual void setReady()
{
com->setReady();
}
};
template<typename T>
class ComDerived : public BaseClass {
protected:
T* com;
public:
void setReady()
{
com->setReady();
}
};
class DerivedClass : public ComDerived<DerivedCom>
{
};
class Derived2Class : public ComDerived<Derived2Com>
{
};
回答4:
Why not templated mother class?
template <typename T>
class BaseClass
{
protected:
T* com;
public:
void setReady()
{
com->setReady();
}
};
class DerivedClass : BaseClass<DerivedCom>
{
};
class Derived2Class : BaseClass<Derived2Com>
{
};
回答5:
To build on d909b's answer, I'd do something like:
class BaseClass {
private:
virtual Com * alloc_com() {
return new Com;
}
Com * com;
public:
BaseClass() : com(alloc_com()) {}
void setReady() {
com->setReady();
}
};
class DerivedClass {
private:
virtual Com * alloc_com() override {
return new DerivedCom;
}
};
class Derived2Class {
private:
virtual Com * alloc_com() override {
return new Derived2Com;
}
};
This works as long as DerivedCom publicly inherits from Com AND when Com has a virtual destructor. If Com does not have a virtual destructor, you also need to have a virtual dealloc_com function. Otherwise, you need to use a template or CRTP pattern, and then you're limited to cases where you are able to deduce the type of the object at compile time. If you know these are your only cases though, using templates will allow you to use the interface without adding virtual function call overhead.
来源:https://stackoverflow.com/questions/13454756/polymorphic-object-members