-2

Suppose I have a large class hierarchy as a single rooted tree, with root being class A such that each of its offsprings has its own implementation of void f(...) and void g(...), with different argument lists.

I have another class class X: public A that only uses the base class f(...) and g(...) in some of its methods. Now I want to extend methods in X to all subtype of A: say the subtype of A be B, the new class is class BX. The requirement is:

  1. (implementation) class BX should use f(...) and g(...) from class B, and all methods from class X.
  2. (interface) class BX should adhere to the interface of class A.

The solution I came up with is to have template<typename B> class BX: public B to avoid the diamond problem in 1.

Is there a better way to achieve what I want?

Cœur
  • 37,241
  • 25
  • 195
  • 267
user103500
  • 77
  • 1
  • 8

2 Answers2

0

In my experience quite a few problems with inheritance go away if you only inherit interfaces (i.e virtual only) and use composition and delegation to share implementations, however the curiously recurring template pattern or CRTP, which is what you've used here is another common way of working around this problem.

phillip voyle
  • 1,863
  • 2
  • 15
  • 18
  • Hi can you explain why this is CRTP? I am forming only one more subtype `BX` for each subtype `B` of `A` here. – user103500 Nov 03 '18 at 19:04
0
template<class D>
struct X {
  A* self(){ return static_cast<D*>(this); }
  A const* self() const{ return static_cast<D*>(this); }
  void foo(){
    self()->f( 1, 2, 3 );
  }
};

struct XA: A, X<XA> {};
struct XB: B, X<XB> {};

Within X<XB>, the implementation of XB, you only have access to A.

If you want users to only see A only expose XBs as an A.

Note this might be quite useless, as accessing any changes in XB/X<XB> requires knowing your object isn't an A, as X<XB> doesn't modify anything in A's interface.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Can you explain why do I need one more level of indirection with `struct X`? Is it to cast `XB` as `A`? Also if `A::f(int, int)` and `B::f(double, double)`, should I add two function `void A::foo() {dof();}; virtual void A::dof() {};` to `class A` and implement `dof()` for each subtype `B` of `A`? – user103500 Nov 03 '18 at 19:10
  • 1
    @user You seemed to want to restrict the implementation of `X` to only using `A` interface. I tried to do that. – Yakk - Adam Nevraumont Nov 03 '18 at 20:02
  • I see. I am reading C++PL section 27.4.1 and I can see what you are doing here now. – user103500 Nov 04 '18 at 01:11