我有以下问题。我有一个基类和几个继承自它的类。所有这些类都共享一个非常相似的接口,很可能不需要重载大多数共享方法。
但是,所有这些都使用了彼此派生的不同成员对象,并且共享一个非常相似的界面。
class BaseClass
{
protected:
Com* com;
public:
void setReady()
{
com->setReady();
}
}
class DerivedClass : BaseClass
{
protected:
DerivedCom* com;
}
class Derived2Class : BaseClass
{
protected:
Derived2Com* com;
}
如何让DerivedClass
让setReady()
运行其com
版本,而不是从BaseClass
继承的版本?
答案 0 :(得分:4)
使用Com的不同实现构造您的实例。 (假设DerivedCom实现了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)
{}
}
答案 1 :(得分:2)
一个简单的解决方案是引入一个getCom()
受保护的虚拟函数,该函数返回Com*
或Com&
:
virtual Com* getCom()
{ return this->com; }
子类可以覆盖它并返回它们自己的Com派生实例。然后,您的setReady()
函数可以实现为:
void setReady()
{
getCom()->setReady();
}
然后您的com
会员可以private
,顺便说一句。
此解决方案的缺点是您将在子类中拥有多个Com
派生的实例。
答案 2 :(得分:1)
也许类模板可能对您有所帮助:
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>
{
};
答案 3 :(得分:0)
为什么不模仿母亲班?
template <typename T>
class BaseClass
{
protected:
T* com;
public:
void setReady()
{
com->setReady();
}
};
class DerivedClass : BaseClass<DerivedCom>
{
};
class Derived2Class : BaseClass<Derived2Com>
{
};
答案 4 :(得分:0)
基于d909b的答案,我会做类似的事情:
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;
}
};
只要DerivedCom公开继承Com Com并且Com具有虚拟析构函数,这就有效。如果Com没有虚拟析构函数,则还需要具有虚拟dealloc_com函数。否则,您需要使用模板或CRTP模式,然后您将局限于能够在编译时推断出对象类型的情况。如果你知道这些是你唯一的例子,使用模板将允许你使用界面而不增加虚函数调用开销。