inheritance question

M

marv

If I have abstract base classes like these:

//---------

class IBase
{
public:
virtual void Action(void) = 0;
};

class IDerived : public IBase
{
public:
virtual void Whatever(void) = 0;
};

//-------

....I expected to be able to create implentations as follows...

//-------


class CBase : public IBase
{
public:
void Action(void) { // do something }
};

class CDerived : public IDerived, public CBase
{
public
void Whatever(void) { // do something else }
};

//-------

....thinking that the IBase::Action() in CDerived (inherited from
IDerived) would be satisfied by the CBase implementation, but I get a
"cannot allocate an object of type CDerived" error as IBase::Action()
is still abstract.

I bet this is to do with them having different entries in the v-table
or something? Like there's an entry for CBase::Action() in CDerived,
but not IBase::Action(), so the linker isn't satisfied. Is there any
way I can fix this without having to declare "void Action(void)" in
CDerived as well? My real code will have many such inherited methods
and I don't want to have to reimplement them all each time, doesn't
that defeat the object of inheritance? I need pure virtual interfaces
to all my classes, and also the inherited structure of the
implementations.

I'm sure this is quite simple, but any advice would be much appreciated!
 
?

=?ISO-8859-1?Q?Ney_Andr=E9_de_Mello_Zunino?=

marv wrote:

[...]
I'm sure this is quite simple, but any advice would be much appreciated!

I can't provide you the exact rationale for I lack the details, but I
will try to help anyway. The class hierarchy you presented creates a
situation where an instance of CDerived will actually have two instances
of the IBase class.

IBase
|
/ \
/ \
/ \
IDerived CBase
\ /
\ /
\ /
|
CDerived

This type of class structure is known as a "diamond hierarchy". The
duplication of IBase in CDerived can be eliminated by using virtual
inheritance, i.e., IDerived and CBase should both derive virtually from
IBase. The following is an updated version of the program:

class IBase
{
public:
virtual void Action(void) = 0;
};

class IDerived : virtual public IBase
{
public:
virtual void Whatever(void) = 0;
};

class CBase : virtual public IBase
{
public:
void Action(void) {}
};

class CDerived : public IDerived, public CBase
{
public:
void Whatever(void) {}
};

int main()
{
CDerived d;
}

Speculation: before using virtual inheritance, there were actually 2
/void Action()/ abstract member functions to be defined, one for each
copy of IBase in CDerived. Your CBase class implemented one of them
only, hence the compiler's complaint. When virtual inheritance enters
the scene, there is only one Action() to be defined.

Sorry about my naive (if at all sane) explanation, but that's what I can
do at the moment. I am sure I will also learn from the experts' advice.

Best regards,
 
D

David White

marv said:
If I have abstract base classes like these:

//---------

class IBase
{
public:
virtual void Action(void) = 0;
};

class IDerived : public IBase
{
public:
virtual void Whatever(void) = 0;
};

//-------

...I expected to be able to create implentations as follows...

//-------


class CBase : public IBase
{
public:
void Action(void) { // do something }
};

class CDerived : public IDerived, public CBase
{
public
void Whatever(void) { // do something else }
};

//-------

...thinking that the IBase::Action() in CDerived (inherited from
IDerived) would be satisfied by the CBase implementation, but I get a
"cannot allocate an object of type CDerived" error as IBase::Action()
is still abstract.

I bet this is to do with them having different entries in the v-table
or something?

No, you've got two copies of IBase and you've only overridden the pure
virtual Action() in one of them. In the line of inheritance CDerived -->
IDerived --> IBase you don't override it, so CDerived is an abstract class.
If you use virtual inheritance of IBase for IDerived and CBase you'll have
only one copy of IBase, shared by IDerived and CBase, and you won't get an
error, i.e.,
class IDerived : virtual public IBase
class CBase : virtual public IBase
Like there's an entry for CBase::Action() in CDerived,
but not IBase::Action(), so the linker isn't satisfied.

You haven't got to the linking stage yet. It's the compiler that's not
happy.
Is there any
way I can fix this without having to declare "void Action(void)" in
CDerived as well? My real code will have many such inherited methods
and I don't want to have to reimplement them all each time, doesn't
that defeat the object of inheritance?

It's simple. To create an object of a given class you have to provide a
non-pure override somewhere of each pure virtual function in each base
class. If you've got two copies of a given base class that are independent
of each other, then any pure virtual in it must be overridden in each copy.
After all, you could have a pointer to either of the bases and call the
function through that pointer.
I need pure virtual interfaces
to all my classes, and also the inherited structure of the
implementations.

I'm sure this is quite simple, but any advice would be much
appreciated!

DW
 

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,968
Messages
2,570,149
Members
46,695
Latest member
StanleyDri

Latest Threads

Top