0

I'm trying to achieve the following inheritance relation.

         Variable
       /         \
... GlobalVar  LocalVar ...
       \         / (either)
       ExtendedVar // Essentially with more fields

I basically want it to extend one of the subclass of Variable, and the choice is made at run time. The virtual inheritance doesn't fully solve the problem. If ExtendedVar inherits both GlobalVar and LocalVar and when I need to call some member funciton, I can't specify which base class to use for the function.

This code seems to work.

class ExtendedVar : public Variable /* ExtendedVar is-a Variable */ {
    Variable& var; // wraps a var in it. This is the var to extend.
    std::string some_field;
}

But it comes with an unnecessary copy of A in the inheritance. Or I could have a few more classes like ExtendedGlobalVar and ExtendedLocalVar, which are obviously bad for maintainence.

Any better options?

YiFei
  • 1,752
  • 1
  • 18
  • 33
  • 1
    https://stackoverflow.com/questions/49002/prefer-composition-over-inheritance – Cory Kramer Aug 01 '17 at 13:22
  • 1
    It's not quite clearly what you are actually trying to do, but you probably want a member `A*` (or some smart variant, or `A&`) in `D` instead of inheritance. – Baum mit Augen Aug 01 '17 at 13:23
  • @CoryKramer, Thanks for the link, yet I want both full interface of A, and to extend one of the subclasses of A... – YiFei Aug 01 '17 at 13:24
  • If D inherits both B and C, D is a subclass of B and C. The object will never be B or C, because it is already an instance of D. So you can always tell D is never B or C. Be precise in your formulation. – Matthias Aug 01 '17 at 13:24
  • *"Any better options?"* What's wrong with this one? In what way does it fail to meet your requirements, whatever those might be? In fact, why don't you describe the X - the problem you are really trying to solve - rather than the Y in your [XY problem](http://xyproblem.info/)? – Igor Tandetnik Aug 01 '17 at 13:26
  • What do you mean by "'extending at run time"? – AndyG Aug 01 '17 at 13:35
  • @AndyG, extend at compile time but choose to extend which at run-time. – YiFei Aug 01 '17 at 13:35
  • @YiFei: I feel stupid for asking because I'm definitely missing something here, but your statement reads like a contradiction to me. Can you explain a little more about what it means to "extend at run-time"? – AndyG Aug 01 '17 at 13:37
  • @AndyG, please see the edited example there. The `ExtendedVar` essentially adds a new field called `some_field` to any of subclass of A, while it the actual type of `var` is determined at run-time. – YiFei Aug 01 '17 at 13:40

1 Answers1

2

I basically want it to extend one of the subclass of Variable, and the choice is made at run time.

To have run time polymorphism, you must refer to an object indirectly. Bases cannot be indirect, but regular members can. Therefore the inheritance that you suggest is not possible, but composition is:

struct ExtendedVar {
    std::unique_ptr<Variable> var;
};

Or I could have a few more classes like ExtendedGlobalVar and ExtendedLocalVar, which are obviously bad for maintainence.

If that is an option (even if a bad one), then it sounds like the choice of base doesn't have to be done at run time.

In that case, you can use a template to generate classes with a base of your choosing, without having to maintain each variant separately:

template <class Base>
struct ExtendedVar : Base {
    // things common to all extended variables
};

ExtendedVar<GlobalVar> an_extended_global_variable;
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Wait... Can I have a common base class for the templated `ExtendedVar`? – YiFei Aug 01 '17 at 13:50
  • @YiFei whoops. what I've shown is not CRTP at all :D It is just a regular template. With this approach, as long as the template argument inherits the common base, then so will the class instantiated from the template. There is no compile time check, but should be do-able with `enable_if`. – eerorika Aug 01 '17 at 13:53
  • :) This is not called CRTP then, just templated inheritance. But the thing is, ExtendedVar have some property some function depend on and will process a bunch of ExtendedVar stored in a container maybe. So that I'll need to identify them with a distinct base class for all ExtendedXXX. – YiFei Aug 01 '17 at 13:59
  • @YiFei sure, you can add a non-template base to ExtendedVar that will then be implemented by all instances, but not by non-extended variabless. – eerorika Aug 01 '17 at 14:02
  • @YiFei although, note that those references to base of `ExtendedVar` cannot use those objects as `Variable`s, unless that base also inherits `Variable`. Which you can do, but then you need to inherit it virtually. – eerorika Aug 01 '17 at 14:35