Given legacy code, the system has the following hierarchy of classes:
Base
^
|
----------+---------------
^ ^ ^ ^ ^
| | | | |
A1 B1 C1 D1 E1
^ ^ ^ ^ ^
| | | | |
A2 B2 C2 D2 E2
.......
^ ^ ^ ^ ^
| | | | |
An Bn Cn Dn En
The hierarchy represents messages in some specific domain.
Base class is of course base class of all messages. A1..E1 are messages belonging to version 1 of the domain, A2..E2 to version 2, and so on. Please note that An must inherit directly from An-1, since An overrides specific methods of An-1.
There's some functionality that is common to all messages, so it's defined as Base::PerformFunctionality. Some part of the functionality is specific to version n only, so there's virtual function Base::SpecificPartOfFunctionality, which is called by Base::PerformFunctionality.
So my problem is how to override Base::SpecificPartOfFunctionality by all An..En.
I see 2 possible solutions, which I don't like too much:
Implement Base::SpecificPartOfFunctionality in each and each An..En.
The problem with this solution is that the implementation should be exactly same for each class, so I just repeat the code.
Additional problem is that if a new class Fn is introduced, developer may forget to implement SpecificPartOfFunctionality.
Introduce BaseN class deriving from Base, while each An..En derive from BaseN too:
class BaseN : public Base {
//...
SpecificPartOfFunctionality() { ...}
};
class An: public An-1, public BaseN { .. }
The problem with this solution is that it introduces diamond problem.
Additional problem is what will happen if some other version m needs to override Base::SpecificPartOfFunctionality too. Following the solution we'll introduce BaseM, which will override Base::SpecificPartOfFunctionality. So which SpecificPartOfFunctionality will be called for An - of BaseN or of BaseN. It's complete mess.
Any suggestions?
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> {};
The only downside is you can't easily forward constructors in current C++, and are probably going to always use the default constructor for A2 and B2 just for simplicity.
In C++0x, however, you can forward constructors:
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) {}
};
Please note that An must inherit directly from An-1, since An overrides specific methods of An-1.
You have misunderstood something. An does not need to inherit directly from An-1. For example, this works just fine:
struct Example {
virtual void f();
};
template<class B>
struct Intermediate : B {};
struct Concrete : Intermediate<Example> {
virtual void f(); // Overrides Example::f.
};
Remember that if this didn't work, then your An couldn't override SpecificPartOfFunctionality from your Base class in the first place! An doesn't directly inherit from Base in any of your examples.
Define a friend function at global scope which implements the functionality, and have SpecificPartsOfFunctionality
do nothing more than call it. E.g.
void FunctionalityN(Base* b)
{
b->DoThings();
...
}
class An : public Base
{
friend void FunctionalityN();
virtual void SpecificPartOfFunctionality() { FunctionalityN(this); }
....
};
Strictly speaking FunctionalityN wouldn't even have to be a friend, though it would make things easier. This makes extending to Fn, Gn, etc. straightforward and subsequently replacing FunctionalityN
with NewFunctionalityN
pretty easy, too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With