【发布时间】:2014-12-30 16:39:03
【问题描述】:
我经常面对这个问题。假设我有这些课程:
class B
{
public:
virtual std::string className(){return "B";}
};
class A
{
public:
A()
: _B(new B)
{}
virtual std::string className(){return "A";}
virtual void desc()
{
std::cout << "I am " << className() <<
" and I own: " << _B->className() << std::endl;
}
protected:
B * _B;
};
然后,我想用新信息扩展A 和B。我确信SuperA 和SuperB 分别与A 和B 具有“is-a”关系。直接的方法是尝试继承:
class SuperB: public B
{
public:
virtual std::string className(){return "SuperB";}
}
class SuperA: public A
{
public:
SuperA()
: A()
, _superB(new SuperB)
{}
virtual std::string className(){return "SuperA";}
virtual void desc()
{
std::cout << "I am " << className() <<
" and I own: " << _superB->className() << std::endl;
}
protected:
SuperB * _superB;
};
但这显然不好,因为SuperA 实际上有两个Bs:一个来自A 类,另一个来自SuperB 类。而desc 的覆盖就没那么优雅了。
我可以看到我可以在 B* 中的 A 中设置 setter 和 getter,并在 SuperA 中覆盖它们以使用 SuperB 而不是 B,并且永远不要直接引用 B*并且总是使用 getter,但这对于 A 来说似乎有点干扰。
尝试编写,即让 SuperA 拥有一个 A* 实例看起来也不好。
如果A 拥有的不是一个B* 而是一个std::vector<B*>,那就更难了。
这是一个常见问题吗?有没有我看不到的优雅解决方案?
【问题讨论】:
-
为什么你不能在
A中有一个接受B指针的受保护的c'tor?然后用它来构造superA的A子对象superB? -
您可以在
SuperA中使用_superB的任何地方使用static_cast或dynamic_cast。不优雅,但可能足以满足您的目的? -
@StoryTeller 这是一个解决方案。不过这对 A 来说有点麻烦。
-
我认为解决问题的一种方法是
A和SuperA类有两个职责:它们分别将B或SuperB适配到其他接口,和 他们管理B或SuperB对象的生命周期。您可以通过仅提供转换 ctorA(B*)等来拆分这些职责,然后提供另一种类型来管理这些对象的生命周期。 -
@RedWark,可能是这样,但恕我直言,这并不比从一开始就拥有一个受保护的成员更具侵入性。
标签: c++ inheritance composition