Inheritcance, references, constructors

S

Simon Elliott

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?
 
V

Victor Bazarov

Simon Elliott said:
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
 
S

Simon Elliott

On 08/02/2005, Victor Bazarov wrote:
[snip]
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.
I am sorry, what's a "bengist"?

Just another arbitrary class.
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.
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?
 
V

Victor Bazarov

Simon said:
[...]
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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top