The best option I can see if you want to stick to your inheritance hierarchy is to implement protected constructors taking a reference which they'll forward to the Base
class. Making a constructor protected makes sure that a (final) instance can't be constructed using this constructor, so it will only be used in subclasses to initialize the super classes.
With some more or less ugly and dangerous macro, this becomes easy to be written:
#define REF_FORWARD_CTOR(ClassName, DirectSuperClassName) \
protected: ClassName(class Ref &r) : DirectSuperClassName(r) {} \
public:
class A : public Base
{
REF_FORWARD_CTOR(A, Base)
public:
A() : Base(refObjectForA) {} // normal ctor
};
class B : public A
{
REF_FORWARD_CTOR(B, A)
public:
B() : A(refObjectForB) {} // normal ctor
};
An alternative design would be to let A
and B
both derive (directly) from Base
. Then, add functionalities by using multiple inheritance and "common classes", maybe private, depending on what they are for:
class Base {
};
class Common {
// common stuff used by both A and B
};
class A : public Base, public Common {
// no further stuff here
};
class B : public Base, public Common {
// add more stuff, or put it in a common super-class again,
// if some classes want to inherit from B again
};
The problem with this design is that functionality in Common
can't access the stuff in A
and B
. To solve this, do one of the following:
- If only static stuff is required: Use CRTP to specify
A
/B
in a concreteCommon
type:Common<A>
can then useA::...
, but doesn't have anything to do with a concrete instance ofA
- If an instance is required: provide a pointer / reference in the constructor of
Common
(slight overhead) - Putting the first two solutions together: Use CRTP, implement wrapper functions in
A
andB
which call functions inCommon<A>
andCommon<B>
providingthis
(which is aA*
orB*
via an extra parameter. - Same as above, but the class
Common
can also be non-templated (no CRTP) if you overload / template these functions on this pointer argument ("CRTP on functions", if you want to call it like that). Code speaks louder than words. (Example code is without your references and focuses on the "common class".)