鉴于遗留代码,系统具有以下类的层次结构:
Base
^
|
----------+---------------
^ ^ ^ ^ ^
| | | | |
A1 B1 C1 D1 E1
^ ^ ^ ^ ^
| | | | |
A2 B2 C2 D2 E2
.......
^ ^ ^ ^ ^
| | | | |
An Bn Cn Dn En
层次结构表示某个特定域中的消息。
Base 类当然是所有消息的基类。 A1..E1是属于域的版本1,A2..E2到版本2的消息,依此类推。请注意,An必须直接从An-1继承,因为An会覆盖An-1的特定方法。
所有消息都有一些共同的功能,因此它被定义为 Base :: PerformFunctionality 。功能的某些部分仅针对版本 n ,因此存在虚拟函数 Base :: SpecificPartOfFunctionality ,由 Base :: PerformFunctionality 调用
所以我的问题是如何通过所有An..En覆盖 Base :: SpecificPartOfFunctionality 。
我看到了两种可能的解决方案,我不太喜欢这些解决方案:
在每个An..En中实现 Base :: SpecificPartOfFunctionality 。
这个解决方案的问题是每个类的实现应该完全相同,所以我只重复代码。
另外一个问题是,如果引入了新的类Fn,开发人员可能会忘记实现 SpecificPartOfFunctionality 。
介绍从Base派生的 BaseN 类,而每个An..En也派生自 BaseN :
class BaseN : public Base {
//...
SpecificPartOfFunctionality() { ...}
};
class An: public An-1, public BaseN { .. }
此解决方案的问题在于它引入了 diamond 问题。
如果其他版本 m 需要覆盖 Base :: SpecificPartOfFunctionality ,还会出现其他问题。根据解决方案,我们将介绍 BaseM ,它将覆盖 Base :: SpecificPartOfFunctionality 。那么将为 BaseN 或 BaseN 的 An 调用 SpecificPartOfFunctionality 。这完全是一团糟。
有什么建议吗?
答案 0 :(得分:3)
struct Base {
virtual void PerformFunctionality() {
stuff();
SpecificPartOfFunctionality();
more_stuff();
}
private:
virtual void SpecificPartOfFunctionality() {}
};
template<class Prev>
struct Version3 : Prev {
protected: // Not private if v4's override might need to call this.
virtual void SpecificPartOfFunctionality() {
v3_specific_stuff();
}
};
struct A1 : Base {};
struct A2 : A1 {};
struct A3 : Version3<A2> {};
struct B1 : Base {};
struct B2 : B1 {};
struct B3 : Version3<B2> {};
唯一的缺点是你不能轻易地在当前的C ++中转发构造函数,并且为了简单起见,它们可能总是使用A2和B2的默认构造函数。
但是,在C ++ 0x中,您可以转发构造函数:
template<class Prev>
struct Version3 : Prev {
using Prev::Prev;
//...
};
struct C2 : C1 {
C2(int); // No default constructor.
};
struct C3 : Version3<C2> {
C3() : Version3<C2>(42) {}
};
请注意,An必须直接从An-1继承,因为An会覆盖An-1的特定方法。
你误会了什么。 An不需要从An-1直接继承 。例如,这很好用:
struct Example {
virtual void f();
};
template<class B>
struct Intermediate : B {};
struct Concrete : Intermediate<Example> {
virtual void f(); // Overrides Example::f.
};
请记住,如果此没有工作,那么您的An无法首先覆盖Base类中的SpecificPartOfFunctionality!在任何示例中,An都不直接从Base继承。
答案 1 :(得分:1)
在全局范围内定义一个实现该功能的友元函数,让SpecificPartsOfFunctionality
除了调用它之外什么也不做。 E.g。
void FunctionalityN(Base* b)
{
b->DoThings();
...
}
class An : public Base
{
friend void FunctionalityN();
virtual void SpecificPartOfFunctionality() { FunctionalityN(this); }
....
};
严格来说,功能N甚至不必是朋友,但它会让事情变得更容易。这样可以直接扩展到Fn,Gn等,然后用FunctionalityN
替换NewFunctionalityN
非常简单。