Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive composition in c++

In my C++ project I often has the following situation, where I have a Class A which has a pointer to the interface of another class X. That class A is extended to handle a subtype of X. And this situation repeats again.

Note that at each layer the interface changes (new object methods are added, and some others are overloaded), so at each subclass of A, the pointer to X is cast to the the subclass of X

+----------+                   +----------+
|          |    A has X        |          |
|   A      +------------------->    X     |
+-----+----+                   +-----+----+
      |                              |
      |                              |
      |                              |
+-----+----+                   +-----+----+
|          |                   |          |
|    B     +------------------->     Y    |
+-----+----+                   +-----+----+
      |                              |
+-----+----+                   +-----+----+
|          |                   |          |
|   C      +------------------->    Z     |
+----------+                   +----------+

I wonder if there is any pattern to deal with this situation, or is it intrinsically a bad design?

EDIT, consider this structure:

+----------+          +----------+                   +----------+
|          |          |          |    A has X        |          |
|    M     <----------+   A      +------------------->    X     |
+-----+----+          +-----+----+                   +-----+----+
      |                     |                              |
      |                     |                              |
      |                     |                              |
+-----+----+          +-----+----+                   +-----+----+
|          |          |          |                   |          |
|     N    <----------+    B     +------------------->     Y    |
+-----+----+          +-----+----+                   +-----+----+ 
      |                     |                              |
+-----+----+          +-----+----+                   +-----+----+
|          |          |          |                   |          |
|    L     <----------+   C      +------------------->    Z     |
+----------+          +----------+                   +----------+

This is actually how might application looks. Each level represent a layer in our multi-layered framework.

like image 961
Vicente Bolea Avatar asked Jun 11 '26 03:06

Vicente Bolea


1 Answers

Consider this implementation:

struct X {};    
struct Y: X {};
struct Z: X {};

class A
{
    // todo: add public interface
protected:
    std::unique_ptr<X> x_;
};

template<typename T>
class AImpl: public A
{
protected:
    T* get() { return dynamic_cast<T*>(x_.get()); }
};

class B: public AImpl<Y>
{
public:
    // todo: add public interface
    using AImpl<Y>::get; // implement rest of B in terms of this
};

class C: public AImpl<Z>
{
public:
    // todo: add public interface
    using AImpl<Z>::get; // implement rest of C in terms of this
};

Edit (because C needs to inherit from B)

Consider defining B and C as follows:

template<typename T>
class BImpl: public AImpl<T>
{
public:
    // todo: add public interface
    using AImpl<T>::get; // implement rest of B in terms of this
};

// this is a new thing (see my explanation on this, below)
using B = BImpl<Y>;

class C: public BImpl<Z>
{
public:
    // todo: add public interface
    using AImpl<Z>::get; // implement rest of C in terms of this
};

There is an issue with implementing B like this though: it is poor design to have your classes do more than one thing. In this case, B would have to be both a base class (for C) and a concrete type.

I created a B implementation class to serve as a base. Then, defining B could be either a type alias (my using statement above), or a concrete type specialization:

class B: public BImpl<Y> {};
like image 170
utnapistim Avatar answered Jun 15 '26 06:06

utnapistim



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!