|
#include <iostream> |
|
|
|
/* How to share implementation of methods between multiple derived classes |
|
without putting it into the base class. Using the curiously recurring template |
|
pattern. |
|
|
|
Let's assume, that most, but not all of the derived classes are implemented in |
|
a similar way, and have .x and .y members. |
|
|
|
It makes sense to write getters and setters only once and share this code |
|
between all implementations. |
|
|
|
Unfortunately, if some of the classes in the hierarchy don't have .x and .y, |
|
we can't put implementation of the getters in the Base class. */ |
|
class Base { |
|
public: |
|
virtual int getX() const = 0; |
|
virtual int getY() const = 0; |
|
}; |
|
|
|
/* Instead we may put the shared implementation into a derived template |
|
class BaseWithGetters which may use template parameter to cast this pointer to |
|
the final class type. */ |
|
template<typename HasXY> |
|
class BaseWithGetters : public Base { |
|
public: |
|
virtual int getX() const { |
|
return static_cast<const HasXY*>(this)->x; |
|
} |
|
virtual int getY() const { |
|
return static_cast<const HasXY*>(this)->y; |
|
} |
|
}; |
|
|
|
/* Final classes which share implementation should be derived from the |
|
template class BaseWithGetters rather than Base. */ |
|
class DerivedA : public BaseWithGetters<DerivedA> { |
|
public: |
|
/* Unfortunately, we have to break encapsulation to allow access to .x and .y |
|
from the base class BaseWithGetters<>. So these implementation details should |
|
be public. */ |
|
int x; |
|
int y; |
|
public: |
|
DerivedA() : x(1), y(2) {} |
|
}; |
|
|
|
class DerivedB : public BaseWithGetters<DerivedB> { |
|
public: |
|
int x; |
|
int y; |
|
public: |
|
DerivedB() : x(10), y(20) {} |
|
}; |
|
|
|
/* Final classes which implement virtual method in a different way, |
|
should be derived from Base class directly. */ |
|
class DerivedNoXY : public Base { |
|
public: |
|
virtual int getX() const { return 100; } |
|
virtual int getY() const { return 200; } |
|
}; |
|
|
|
int main() { |
|
DerivedA a; |
|
DerivedB b; |
|
DerivedNoXY c; |
|
std::cout << "DerivedA.getX() should return 1: " << a.getX() << "\n"; |
|
std::cout << "DerivedA.getY() should return 2: " << a.getY() << "\n"; |
|
std::cout << "DerivedB.getX() should return 10: " << b.getX() << "\n"; |
|
std::cout << "DerivedB.getY() should return 20: " << b.getY() << "\n"; |
|
std::cout << "DerivedNoXY.getX() should return 100: " << c.getX() << "\n"; |
|
std::cout << "DerivedNoXY.getY() should return 200: " << c.getY() << "\n"; |
|
} |