Inheritcance, references, constructors

Discussion in 'C++' started by Simon Elliott, Feb 7, 2005.

  1. A fairly standard polymorphic class which needs a reference to an
    object:

    class bar
    {
    int i1_;
    };

    class fooBase
    {
    public:
    fooBase(bar& barRef):barRef_(barRef){}
    virtual ~fooBase();
    private:
    bar& barRef_;
    int i1_;
    };

    class fooDerived1:public fooBase
    {
    public:
    fooDerived1(bar& barRef):fooBase(barRef){}
    private:
    int i2_;
    };

    int main(int argc, char* argv[])
    {
    bar myBar;
    fooBase* myFooBase = new fooDerived1(myBar);
    delete myFooBase;
    return 0;
    }

    Fine as far as it goes, but if you end up with several dozen or several
    hundred fooDerivedN, maintenance becomes a bit tedious.

    Let's say you wanted to add a reference to a bengist as well as a bar.
    You have to change every single constructor of
    fooDerived1..fooDerivedN. And if this is part of a large project with
    several developers, you have to check out all these files meaning
    no-one else can be working on them. Even if the change only takes 5
    minutes this can be very disruptive.

    Admittedly the compiler will let you know if you've missed one, but to
    me it seems untidy to have to change constructors of lots of derived
    classes. Is there a better way?

    --
    Simon Elliott http://www.ctsn.co.uk
    Simon Elliott, Feb 7, 2005
    #1
    1. Advertising

  2. "Simon Elliott" <Simon at ctsn.co.uk> wrote...
    >A fairly standard polymorphic class which needs a reference to an
    > object:
    >
    > class bar
    > {
    > int i1_;
    > };
    >
    > class fooBase
    > {
    > public:
    > fooBase(bar& barRef):barRef_(barRef){}
    > virtual ~fooBase();
    > private:
    > bar& barRef_;
    > int i1_;


    i1_ is left uninitialised. Did you intend to have it here?

    > };
    >
    > class fooDerived1:public fooBase
    > {
    > public:
    > fooDerived1(bar& barRef):fooBase(barRef){}
    > private:
    > int i2_;
    > };
    >
    > int main(int argc, char* argv[])
    > {
    > bar myBar;
    > fooBase* myFooBase = new fooDerived1(myBar);
    > delete myFooBase;
    > return 0;
    > }
    >
    > Fine as far as it goes, but if you end up with several dozen or several
    > hundred fooDerivedN, maintenance becomes a bit tedious.
    >
    > Let's say you wanted to add a reference to a bengist as well as a bar.


    I am sorry, what's a "bengist"?

    > You have to change every single constructor of
    > fooDerived1..fooDerivedN. And if this is part of a large project with
    > several developers, you have to check out all these files meaning
    > no-one else can be working on them. Even if the change only takes 5
    > minutes this can be very disruptive.


    Just like changing any other _interface_ of any base class from which
    there are many derived classes. There should be no surprise.

    > Admittedly the compiler will let you know if you've missed one, but to
    > me it seems untidy to have to change constructors of lots of derived
    > classes. Is there a better way?


    No, there isn't. Changing interface is a maintenance nightmare. Just
    be ready for it.

    V
    Victor Bazarov, Feb 8, 2005
    #2
    1. Advertising

  3. On 08/02/2005, Victor Bazarov wrote:
    [snip]
    > > class fooBase
    > > {
    > > public:
    > > fooBase(bar& barRef):barRef_(barRef){}
    > > virtual ~fooBase();
    > > private:
    > > bar& barRef_;
    > > int i1_;

    >
    > i1_ is left uninitialised. Did you intend to have it here?


    I included i1_ just to illustrate that fooBase will have other data
    members and methods.

    > > Fine as far as it goes, but if you end up with several dozen or
    > > several hundred fooDerivedN, maintenance becomes a bit tedious.
    > >
    > > Let's say you wanted to add a reference to a bengist as well as a
    > > bar.

    >
    > I am sorry, what's a "bengist"?


    Just another arbitrary class.

    > > You have to change every single constructor of
    > > fooDerived1..fooDerivedN. And if this is part of a large project
    > > with several developers, you have to check out all these files
    > > meaning no-one else can be working on them. Even if the change only
    > > takes 5 minutes this can be very disruptive.

    >
    > Just like changing any other interface of any base class from which
    > there are many derived classes. There should be no surprise.


    I'm not surprised, just wondered if there was a better way.

    > > Admittedly the compiler will let you know if you've missed one, but
    > > to me it seems untidy to have to change constructors of lots of
    > > derived classes. Is there a better way?

    >
    > No, there isn't. Changing interface is a maintenance nightmare. Just
    > be ready for it.


    The only thing that occurs to me is to contain the references
    somewhere. Something like this (untested):

    struct fooBaseInits
    {
    fooBaseInits(bar& barRef, bengist& bengistRef):
    barRef_(barRef),bengistRef_(bengistRef){}
    bar& barRef_
    bengist& bengistRef_;
    };

    class fooBase
    {
    public:
    fooBase(fooBaseInits& inits):
    barRef_(inits.barRef_),bengistRef_(inits.bengistRef_){}
    virtual ~fooBase();
    private:
    bar& barRef_;
    bengist& bengistRef_;
    };

    class fooDerived1:public fooBase
    {
    public:
    fooDerived1(fooBaseInits& inits):fooBase(inits){}
    private:
    };

    Then we can make as many changes as we want to fooBaseInits and the
    rest of the code doesn't need to change. In fact for many of the
    derived classes fooBaseInits can just be a forward declaration...

    Any thoughts?

    --
    Simon Elliott http://www.ctsn.co.uk
    Simon Elliott, Feb 8, 2005
    #3
  4. Simon Elliott wrote:
    > [...]
    > The only thing that occurs to me is to contain the references
    > somewhere. Something like this (untested):
    >
    > struct fooBaseInits
    > {
    > fooBaseInits(bar& barRef, bengist& bengistRef):
    > barRef_(barRef),bengistRef_(bengistRef){}
    > bar& barRef_
    > bengist& bengistRef_;
    > };
    >
    > class fooBase
    > {
    > public:
    > fooBase(fooBaseInits& inits):
    > barRef_(inits.barRef_),bengistRef_(inits.bengistRef_){}
    > virtual ~fooBase();
    > private:
    > bar& barRef_;
    > bengist& bengistRef_;
    > };
    >
    > class fooDerived1:public fooBase
    > {
    > public:
    > fooDerived1(fooBaseInits& inits):fooBase(inits){}
    > private:
    > };
    >
    > Then we can make as many changes as we want to fooBaseInits and the
    > rest of the code doesn't need to change. In fact for many of the
    > derived classes fooBaseInits can just be a forward declaration...
    >
    > Any thoughts?
    >


    OK. Looks good. Now, how do you initialise the reference ('inits') that
    is passed to the constructor of 'fooDerived1' and all other classes that
    derive from 'fooBase'?

    fooBaseInits inits = { some_bar, some_bengist };
    fooDerived1 der(inits);

    now, you need to add 'benbargist' to your initialisation sequence... And
    you're back where you started, looking through all the code for the places
    where 'inits' has to be changed.

    V
    Victor Bazarov, Feb 8, 2005
    #4
    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.
Similar Threads
  1. Dave Rudolf
    Replies:
    12
    Views:
    8,277
    Martijn Lievaart
    Feb 6, 2004
  2. Jeremy Smith
    Replies:
    2
    Views:
    588
    Jeremy Smith
    Aug 3, 2006
  3. Jess
    Replies:
    5
    Views:
    596
    Ron Natalie
    Jun 7, 2007
  4. Peng Yu
    Replies:
    5
    Views:
    393
    Juha Nieminen
    Sep 19, 2008
  5. srp113
    Replies:
    3
    Views:
    465
Loading...

Share This Page