By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,236 Members | 1,833 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,236 IT Pros & Developers. It's quick & easy.

Multiple inheritance: Wrong constructors being called?

P: n/a
Hi everyone,

I'm having some trouble getting the correct chain of constructors to be called when creating an object at the bottom of a hierarchy. Have a look at the code below - the inheritance goes like this:

Shape
|
+-- Ellipse
|
+-- Circle

When I create a new Circle, it calls the Ellipse's constructor, which in turn calls the Shape's constructor. The problem is that I'm passing parameters to the constructors, and the Ellipse's constructor passes these parameters on to the Shape's constructor - but these parameters are ignored and the Shape's default constructor is called instead of the one taking parameters!

What am I doing wrong???

----------------------------------------------
#include <iostream>

class Shape
{
public:
Shape(void)
{
std::cout << "Default shape constructor, should be unused" << std::endl;
}

Shape(int width, int height)
{
std::cout << "Creating a new shape with size " << width << "x" << height << std::endl;
}
};

class Ellipse: virtual public Shape
{
public:
Ellipse(int width, int height):
Shape(width, height)
{
std::cout << "In Ellipse constructor, a shape with size should have already been created above" << std::endl;
}
};

class Circle: virtual public Ellipse
{
public:
Circle(int width, int height):
Ellipse(width, height)
{
std::cout << "In Circle constructor, Ellipse should already have been created above" << std::endl;
}
};

int main(void)
{
Circle *c = new Circle(10, 20);
delete c;
return 0;
}

----------------------------------------------

$ g++ -o test test.cpp && ./test

Default shape constructor, should be unused
In Ellipse constructor, a shape with size should have already been created above
In Circle constructor, Ellipse should already have been created above

----------------------------------------------

Thanks,
Adam.
Mar 11 '07 #1
Share this Question
Share on Google+
7 Replies


P: n/a
Adam Nielsen wrote:
Hi everyone,

I'm having some trouble getting the correct chain of constructors to be called when creating an object at the bottom of a hierarchy. Have a look at the code below - the inheritance goes like this:

Shape
|
+-- Ellipse
|
+-- Circle

When I create a new Circle, it calls the Ellipse's constructor, which in turn calls the Shape's constructor. The problem is that I'm passing parameters to the constructors, and the Ellipse's constructor passes these parameters on to the Shape's constructor - but these parameters are ignored and the Shape's default constructor is called instead of the one taking parameters!

What am I doing wrong???
Using virtual inheritance. Drop the virtual and everything will work as
you expect.

john
Mar 11 '07 #2

P: n/a
Using virtual inheritance. Drop the virtual and everything will work
as you expect.
Ah yes, that worked. I think I'll need to re-think the virtual
inheritance in the rest of my code... :-/

Thanks for your help!

Cheers,
Adam.
Mar 11 '07 #3

P: n/a
Adam Nielsen wrote:
Hi everyone,

I'm having some trouble getting the correct chain of constructors to be called when creating an object at the bottom of a hierarchy. Have a look at the code below - the inheritance goes like this:

Shape
|
+-- Ellipse
|
+-- Circle

When I create a new Circle, it calls the Ellipse's constructor, which in turn calls the Shape's constructor. The problem is that I'm passing parameters to the constructors, and the Ellipse's constructor passes these parameters on to the Shape's constructor - but these parameters are ignored and the Shape's default constructor is called instead of the one taking parameters!

What am I doing wrong???
BTW making a circle inherit from an ellipse is a classic mistake in OO
programming, see here

http://en.wikipedia.org/wiki/Circle-ellipse_problem

Speculating from the code you've posted I would guess that you've
misunderstood the concept of multiple inheritance. Multiple inheritance
means a class having more than one *direct* base class. And there are
situations using multiple inheritance when you also need to use virtual
inheritance, and yes it does change the rules for how constructors are
called.

However multiple inheritance does not mean having an inheritance
hierarchy with a depth of greater than one. That is what the code you
posted has, but it is still simple single inheritance.

john
Mar 11 '07 #4

P: n/a
On 11 Mar, 07:56, Adam Nielsen <a.niel...@shikadi.rem.ove.netwrote:
Hi everyone,

I'm having some trouble getting the correct chain of constructors to be called when creating an object at the bottom of a hierarchy. Have a look at the code below - the inheritance goes like this:

Shape
|
+-- Ellipse
|
+-- Circle

When I create a new Circle, it calls the Ellipse's constructor, which in turn calls the Shape's constructor. The problem is that I'm passing parameters to the constructors, and the Ellipse's constructor passes these parameters on to the Shape's constructor - but these parameters are ignored and the Shape's default constructor is called instead of the one taking parameters!

What am I doing wrong???

----------------------------------------------
#include <iostream>

class Shape
{
public:
Shape(void)
{
std::cout << "Default shape constructor, should be unused" << std::endl;
}

Shape(int width, int height)
{
std::cout << "Creating a new shape with size " << width << "x" << height << std::endl;
}

};

class Ellipse: virtual public Shape
{
public:
Ellipse(int width, int height):
Shape(width, height)
{
std::cout << "In Ellipse constructor, a shape with size should have already been created above" << std::endl;
}

};

class Circle: virtual public Ellipse
{
public:
Circle(int width, int height):
Ellipse(width, height)
{
std::cout << "In Circle constructor, Ellipse should already have been created above" << std::endl;
}

};

int main(void)
{
Circle *c = new Circle(10, 20);
delete c;
return 0;

}

----------------------------------------------

$ g++ -o test test.cpp && ./test

Default shape constructor, should be unused
In Ellipse constructor, a shape with size should have already been created above
In Circle constructor, Ellipse should already have been created above

----------------------------------------------

Thanks,
Adam.
Hiya,

In C++, when you create an instance of a class, virtual base class
constructors are called first. If you don't have an explicit call to
a virtual base class ctor, then the compiler will call it under the
covers *and will use the default [no parameter] constructor*. If you
want it to call a non-default ctor, you must make an explicit call to
the ctor in the initializer list.

So, your Circle has two virtual base classes - Ellipse and Shape. The
standard says that these base classes should be constructed in left-to-
right order depth first search. In your case, that means the compiler
will want to initialize Shape first, then Ellipse. The compiler sees
that you haven't specified an explicit initializer call to a Shape
ctor, so it adds in a call to the default ctor for you.

So, if you add the following to your Circle ctor initializer list:

public:
Circle(int width, int height):
>> Shape(width, height), <<<
Ellipse(width, height)
{

then you end up with what you wanted.

Hope that helps,
Doug

Mar 11 '07 #5

P: n/a
Hi John,
BTW making a circle inherit from an ellipse is a classic mistake in OO
programming
Speculating from the code you've posted I would guess that you've
misunderstood the concept of multiple inheritance.
This code was just an example to illustrate the problem - my real code
is different, but you may have a point. I was using each subclass to
represent a more specific case of each parent (in the same way that an
Ellipse is a more specific version of a Shape.)

This may not be the best way of doing things, but in my particular case
it's certainly the easiest :-)
Multiple inheritance means a class having more than one *direct* base
class. And there are situations using multiple inheritance when you
also need to use virtual inheritance, and yes it does change the rules
for how constructors are called. However multiple inheritance does
not mean having an inheritance hierarchy with a depth of greater than
one. That is what the code you posted has, but it is still simple
single inheritance.
Eventually later on in the program I do use multiple inheritance
properly (e.g. a class may inherit both an Ellipse and a Rectangle,
which would give it two copies of the Shape base class) however having
said that these particular classes will never be multiply inherited - so
there was no need for virtual inheritance here after all (but when
you're still not 100% familiar with the concepts, a rule of thumb like
making all inheritance virtual is really tempting!)

Cheers,
Adam.
Mar 11 '07 #6

P: n/a
Hi Doug,
In C++, when you create an instance of a class, virtual base class
constructors are called first.
Yes, I now realise why that happens.
So, if you add the following to your Circle ctor initializer list:

public:
Circle(int width, int height):
> Shape(width, height), <<<
Ellipse(width, height)
{

then you end up with what you wanted.
I had thought about something like that when the problem was first
pointed out, but I was somewhat reluctant to do it this way - the Circle
isn't really supposed to be aware of the Shape, it's only supposed to
know about the workings of its direct parent class, the Ellipse.

Thanks for your suggestion though!

Cheers,
Adam.
Mar 11 '07 #7

P: n/a
On 11 Mar, 21:57, Adam Nielsen <a.niel...@shikadi.rem.ove.netwrote:
Hi Doug,
In C++, when you create an instance of a class, virtual base class
constructors are called first.

Yes, I now realise why that happens.
So, if you add the following to your Circle ctor initializer list:
public:
Circle(int width, int height):
>> Shape(width, height), <<<
Ellipse(width, height)
{
then you end up with what you wanted.

I had thought about something like that when the problem was first
pointed out, but I was somewhat reluctant to do it this way - the Circle
isn't really supposed to be aware of the Shape, it's only supposed to
know about the workings of its direct parent class, the Ellipse.

Thanks for your suggestion though!

Cheers,
Adam.
Hi Adam,

Totally fair play, mate. I wouldn't have done it either.

Doug

Mar 12 '07 #8

This discussion thread is closed

Replies have been disabled for this discussion.