Inheriting the Wrong Constructor

Discussion in 'C++' started by AalaarDB@gmail.com, Aug 28, 2008.

  1. Guest

    struct base
    {
    int x, y, z;
    base() {x = 0; y = 0; z = 0;};
    base(int x1, int y1, int z1) {x = x1; y = y1; z = z1;};
    };

    struct intermediate1 : public virtual base {};

    struct intermediate2 : public virtual base
    {
    intermediate2() : base(1,2,3) {};
    };

    struct derived : public virtual intermediate2, public virtual
    intermediate1
    {
    derived() : intermediate2() {};
    };

    int main()
    {
    derived temp;
    return 0;
    }

    OK, I know that classes don't actually inherit constructors. But it
    sure seems like derived is inheriting something it shouldn't. When I
    step through derived's instantiation I see that derived calls base's
    default ctor and then calls intermediate2's ctor which does NOT call
    base's custom ctor (I guess since it's already ctored). What I want
    is derived to call intermediate2 to call base custom ctor. Why does
    it do this, and how can I do what I want?
     
    , Aug 28, 2008
    #1
    1. Advertising

  2. Guest

    > Read the FAQ.  Prefer initialisation to assignment.  Also, it would
    > seem that both constructors can be merged:
    >
    >       base(int x = 0, int y = 0, int z = 0) : x(x), y(y), z(z) {}
    >
    > (and learn to omit the semicolons after function bodies).
    >
    >
    > This has nothing to do with inheriting constructors, and everything with
    > the rule that the _most derived class_ is responsible for doing the
    > initialisation of the virtual base class[es].
    >
    > 'derived' has 'base' as virtual base class.  That means it *itself* is
    > responsible for initialising the 'base' subobject.  That means, in turn,
    > that in the initialiser list of 'derived' there *will be* the call to
    > 'base::base()' (implicitly) if you don't specify explicitly what
    > constructor should be used.  It is up to you to do it right, the
    > 'derived' object cannot delegate the responsibility to any of its other
    > base classes.  So, you ought to write
    >
    >      derived() : base(1,2,3) {}
    >
    > if you wanted the particular values to be passed to 'base::base'.



    Thanks for the response but it's not the answer I was looking for. I
    don't want the answer I can't or my design in insufficient, I want the
    answer do x y z to get around it. So what is my reason to want the
    base class initialized by an intermediate class rather than the
    derived class? Because I'm using a policy based design. Let me
    give you a more refined example, and again this is example code so no
    need to worry about other critiques (I knew about all those and I read
    the FAQ).

    enum eShape {
    circle,
    triangle,
    square
    };

    struct baseInteface
    {
    eShape shape;
    baseInteface() {};
    baseInteface(eShape shape) {base::shape = shape;};
    //other stuff related to interface
    };

    namespace Triangle {
    struct InitPolicy : public virtual baseInteface
    {
    InitPolicy() : baseInteface(triangle){};
    };
    struct SomeOtherPolicy {};
    };

    namespace Square {
    struct InitPolicy : public virtual baseInteface
    {
    int height, width;
    InitPolicy() : baseInteface(square){height = 0; width = 0;};
    };
    struct SomeOtherPolicy {};
    };

    template <
    class shapePolicy,
    class otherPolicy
    >

    struct Shape : public virtual shapePolicy, public virtual otherPolicy
    {
    Shape() : shapePolicy() {};
    };

    int main()
    {
    Shape<Triangle::InitPolicy, Triangle::SomeOtherPolicy> shape;
    return 0;
    }


    Here, your suggestion of writing derived() : baseInteface(/*policy
    data*/) {} violates my encapsulation, my derived class should not have
    knowledge of the implementation of any of the policies, baseInteface
    is the interface and derived is just the template conglomerator.

    OK so you might ask me why don't you throw out all those policies and
    intermediate classes and just have class Triangle inherit from class
    Polygon? Because this is an example, I have too many derivations and
    a policy based design cuts that number down. Or you might ask why not
    just bite the bullet and use a virtual OnInit function? Well that's
    what I tried at first, but C++ cannot call virtual functions from
    farther down the inheritance tree in a constructor, because the object
    further down doesn't exist yet!

    So any ideas on how to have some intermediate policy init a base class
    without the derived class knowing about it?
     
    , Aug 28, 2008
    #2
    1. Advertising

  3. James Kanze Guest

    On Aug 28, 6:11 am, wrote:
    > > Read the FAQ. Prefer initialisation to assignment. Also,
    > > it would seem that both constructors can be merged:


    > > base(int x = 0, int y = 0, int z = 0) : x(x), y(y), z(z) {}


    > > (and learn to omit the semicolons after function bodies).


    > > This has nothing to do with inheriting constructors, and
    > > everything with the rule that the _most derived class_ is
    > > responsible for doing the initialisation of the virtual base
    > > class[es].


    > > 'derived' has 'base' as virtual base class. That means it
    > > *itself* is responsible for initialising the 'base'
    > > subobject. That means, in turn, that in the initialiser
    > > list of 'derived' there *will be* the call to 'base::base()'
    > > (implicitly) if you don't specify explicitly what
    > > constructor should be used. It is up to you to do it right,
    > > the 'derived' object cannot delegate the responsibility to
    > > any of its other base classes. So, you ought to write


    > > derived() : base(1,2,3) {}


    > > if you wanted the particular values to be passed to
    > > 'base::base'.


    > Thanks for the response but it's not the answer I was looking for.


    It's the correct answer, however.

    > I don't want the answer I can't or my design in insufficient,
    > I want the answer do x y z to get around it.


    But that's what Victor just gave you. Specify the initializers
    in the most derived class.

    > So what is my reason to want the base class initialized by an
    > intermediate class rather than the derived class?


    Which intermediate class? You can have several intermediate
    classes deriving from the same instance of the virtual base.

    A long, long time ago, John Skaller, Fergus Henderson and I
    discussed the possibility of requiring the compiler to determing
    the lowest common derived class for each virtual base, and
    calling the constructor there. In the end, we didn't follow
    through with a proposal, because it requires a lot more
    complexity in the compiler, and the cases where you would want a
    non empty virtual base (requiring an initializer) are
    exceedingly rare. (Note, however, that there is an example of
    such in the standard library: basic_ios<>. If worse comes to
    worse, you can always use something like is used in the iostream
    hierarchy. Be forewarned, however, that it can be extremely
    tricky to make it work without undefined behavior is some
    special cases.)

    > Because I'm using a policy based design. Let me give you a
    > more refined example, and again this is example code so no
    > need to worry about other critiques (I knew about all those
    > and I read the FAQ).


    > enum eShape {
    > circle,
    > triangle,
    > square
    > };


    > struct baseInteface
    > {
    > eShape shape;
    > baseInteface() {};
    > baseInteface(eShape shape) {base::shape = shape;};
    > //other stuff related to interface
    > };


    > namespace Triangle {
    > struct InitPolicy : public virtual baseInteface
    > {
    > InitPolicy() : baseInteface(triangle){};
    > };
    > struct SomeOtherPolicy {};
    > };


    > namespace Square {
    > struct InitPolicy : public virtual baseInteface
    > {
    > int height, width;
    > InitPolicy() : baseInteface(square){height = 0; width = 0;};
    > };
    > struct SomeOtherPolicy {};
    > };


    > template <
    > class shapePolicy,
    > class otherPolicy


    > struct Shape : public virtual shapePolicy, public virtual otherPolicy
    > {
    > Shape() : shapePolicy() {};
    > };


    > int main()
    > {
    > Shape<Triangle::InitPolicy, Triangle::SomeOtherPolicy> shape;
    > return 0;
    > }


    I don't quite see why you need, or even want, virtual
    inheritance here. All of your shapePolicy should inherit from
    baseInteface (which is in fact BasicShapePolicy). And no other
    classes should. So you really don't want virtual inheritance
    here.

    [...]
    > So any ideas on how to have some intermediate policy init a
    > base class without the derived class knowing about it?


    In simple cases like this, you can simply use an init() member
    function, calling it where ever you want.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Aug 31, 2008
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.

Share This Page