473,387 Members | 1,779 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Multiple inheritance: Wrong constructors being called?

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
7 3703
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
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
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
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
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
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
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Alexander Stippler | last post by:
I've got an inheritance structure with two coupled "dreaded diamonds" like shown below: A / \ / \ B C \ / \ \ / \ D E \ /
4
by: Busin | last post by:
When a child class inherits from a base class, will the child class inherits everything of the base class, including all member variables and functions? Or is such inheritance "selective", like not...
3
by: Gianni Mariani | last post by:
In the code below, controller::controller() is never invoked, however, it appears there is no way to make a compile-time rule that this should not happen. The code below seems to make compilers...
4
by: Xavier | last post by:
Hi, I have a question, in a "dreaded diamond" situation, regarding the following code: ---- Begin code #include <iostream> using namespace std;
22
by: Matthew Louden | last post by:
I want to know why C# doesnt support multiple inheritance? But why we can inherit multiple interfaces instead? I know this is the rule, but I dont understand why. Can anyone give me some concrete...
45
by: Ben Blank | last post by:
I'm writing a family of classes which all inherit most of their methods and code (including constructors) from a single base class. When attempting to instance one of the derived classes using...
5
by: Thomas Girod | last post by:
Hi. I think I'm missing something about multiple inheritance in python. I've got this code. class Foo: def __init__(self): self.x = "defined by foo" self.foo = None
8
by: Robert | last post by:
Hi! So far I have been doing "inheritance" in Javascript like this: ****** function TestObject(value) { this.value = value; }
3
by: Jess | last post by:
Hello, I've been reading Effective C++ about multiple inheritance, but I still have a few questions. Can someone give me some help please? First, it is said that if virtual inheritance is...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.