Multiple Inheritance ambiguity but not really?

N

Nick Overdijk

With this code:

#include <iostream>
using namespace std;

class car {
public:
car (float speed) :
speed(speed) {}

car () :
speed(0) {}

void cruise(float speed) {
this->speed = speed;
cout << "New speed: " << getSpeed() << endl;
}

void brake(float power) {
this->speed -= power*power/4;
}

float getSpeed() {
return speed;
}

private:
float speed;
};

class racer : public car {
public:
void boost(float power) {
cout << "BOOST! ";
cruise(getSpeed() + power*power/3);
}
};

class tank : public car {
public:
bool shoot(float aimTime) {
cout << "Shot ";
if (aimTime > 5.0) {
cout << "hits!" << endl;
return true; //hit!
} else {
cout << "misses!" << endl;
return false; //miss!
}
}

};

class racetank : public racer, public tank {
public:
bool boostShoot(float power, float aimTime) {
boost(power*2);
return shoot(aimTime*2);
}
};

int main() {
racetank mycar;
mycar.car::cruise(50);
mycar.boost(20);
mycar.car::brake(5);
mycar.boostShoot(35, 1.4);

return 0;
}

MinGW's GCC gives me this error, twice:
error: `car' is an ambiguous base of `racetank'

How come the compiler still complains about ambiguity?

It knows the function is not overloaded (?)
It knows the function is not virtual.

Can't the compiler be sure that when I call the function like that, it's
the same function?

I know the solution to this is to use virtual inheritance, but I was
wondering why this happens.

Thanks in advance,
 
N

Nick Overdijk

Nick said:
With this code:

#include <iostream>
using namespace std;

class car {
public:
car (float speed) :
speed(speed) {}

car () :
speed(0) {}

void cruise(float speed) {
this->speed = speed;
cout << "New speed: " << getSpeed() << endl;
}

void brake(float power) {
this->speed -= power*power/4;
}

float getSpeed() {
return speed;
}

private:
float speed;
};

class racer : public car {
public:
void boost(float power) {
cout << "BOOST! ";
cruise(getSpeed() + power*power/3);
}
};

class tank : public car {
public:
bool shoot(float aimTime) {
cout << "Shot ";
if (aimTime > 5.0) {
cout << "hits!" << endl;
return true; //hit!
} else {
cout << "misses!" << endl;
return false; //miss!
}
}

};

class racetank : public racer, public tank {
public:
bool boostShoot(float power, float aimTime) {
boost(power*2);
return shoot(aimTime*2);
}
};

int main() {
racetank mycar;
mycar.car::cruise(50);
mycar.boost(20);
mycar.car::brake(5);
mycar.boostShoot(35, 1.4);

return 0;
}

MinGW's GCC gives me this error, twice:
error: `car' is an ambiguous base of `racetank'

How come the compiler still complains about ambiguity?

It knows the function is not overloaded (?)
It knows the function is not virtual.

Can't the compiler be sure that when I call the function like that, it's
the same function?

I know the solution to this is to use virtual inheritance, but I was
wondering why this happens.

Thanks in advance,

Replying to myself yeey.

Let a class in memory be resembled by:

[classname]

Class inheritance in memory looks like this, according to wikipedia.

class a;
class b : a;

class a looks like this: [a]

b looks like this: [a]

So if we'd have a class base and c, we can create a diamond inheritance:

class base;
class a : base;
class b : base;
class c : a, b;

Their memory-pictures are like this:

base: [base]
a: [base][a]
b: [base]
c: [base][a][base][c]

c, more specific, looks like this: [a::base][a][b::base][c]

So, naturally, a::base and b::base data members can differ, but
a::base::func() must be the same as b::base::func() given that a and b
don't overload and func() is not virtual right? How else can they be
different?
 
N

Nick Overdijk

Pete said:
c, more specific, looks like this: [a::base][a][b::base][c]

So, naturally, a::base and b::base data members can differ, but
a::base::func() must be the same as b::base::func() given that a and b
don't overload and func() is not virtual right? How else can they be
different?


Right. That's why it's ambiguous. You can disambiguate the call with an
explicit class specifier: a::func() and b::func() name two different
functions.


Yeah.. I guess the only question I asked is why the compiler didn't just
pick one. xD Thanks anyway!
 
N

Nick Overdijk

blargg said:
Nick Overdijk wrote:
[...]
So if we'd have a class base and c, we can create a diamond inheritance:

class base;
class a : base;
class b : base;
class c : a, b;

Their memory-pictures are like this:

base: [base]
a: [base][a]
b: [base]
c: [base][a][base][c]

c, more specific, looks like this: [a::base][a][b::base][c]

So, naturally, a::base and b::base data members can differ, but
a::base::func() must be the same as b::base::func() given that a and b
don't overload and func() is not virtual right? How else can they be
different?


[the question was why then is the non-static call c.base::func() ambiguous]

It's ambiguous because a c has two base sub-objects, and you haven't
specified which one you want to invoke base::func() on. The fact that for
either one the same member function would be invoked isn't relevant; it's
the 'this' pointer that is.

Hm, yeah. I understand. Is there a way (besides virtual inheritance) to
have a class that resembles this: [base][a][c] ?
 
J

James Kanze

blargg said:
Nick Overdijk wrote:
[...]
So if we'd have a class base and c, we can create a diamond
inheritance:
class base;
class a : base;
class b : base;
class c : a, b;
Their memory-pictures are like this:
base: [base]
a: [base][a]
b: [base]
c: [base][a][base][c]
c, more specific, looks like this: [a::base][a][b::base][c]
So, naturally, a::base and b::base data members can differ,
but a::base::func() must be the same as b::base::func()
given that a and b don't overload and func() is not virtual
right? How else can they be different?

[the question was why then is the non-static call
c.base::func() ambiguous]
It's ambiguous because a c has two base sub-objects, and you
haven't specified which one you want to invoke base::func()
on. The fact that for either one the same member function
would be invoked isn't relevant; it's the 'this' pointer
that is.

Hm, yeah. I understand. Is there a way (besides virtual
inheritance) to have a class that resembles this:
[base][a][c] ?


I'm not sure I understand the question. What it seems to boil
down to is: is there any way, except the existing way(s), to
have a class [...]. This is what virtual inheritance was
designed for.
 
N

Nick Overdijk

James said:
blargg said:
Nick Overdijk wrote:
[...]
So if we'd have a class base and c, we can create a diamond
inheritance:
class base;
class a : base;
class b : base;
class c : a, b;
Their memory-pictures are like this:
base: [base]
a: [base][a]
b: [base]
c: [base][a][base][c]
c, more specific, looks like this: [a::base][a][b::base][c]
So, naturally, a::base and b::base data members can differ,
but a::base::func() must be the same as b::base::func()
given that a and b don't overload and func() is not virtual
right? How else can they be different?
[the question was why then is the non-static call
c.base::func() ambiguous]
It's ambiguous because a c has two base sub-objects, and you
haven't specified which one you want to invoke base::func()
on. The fact that for either one the same member function
would be invoked isn't relevant; it's the 'this' pointer
that is.

Hm, yeah. I understand. Is there a way (besides virtual
inheritance) to have a class that resembles this:
[base][a][c] ?


I'm not sure I understand the question. What it seems to boil
down to is: is there any way, except the existing way(s), to
have a class [...]. This is what virtual inheritance was
designed for.

--
James Kanze (GABI Software) email:[email protected]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Not the existing ways, the ways that I know of. Other ways besides the
ways that I know of to do that. If virtual inheritance is the only way
then fine, I was just wondering.

Thanks for everyone's help, think I understand it now. Are there any
pitfalls when using a lot of virtual inheritance?
 
J

James Kanze

James said:
Hm, yeah. I understand. Is there a way (besides virtual
inheritance) to have a class that resembles this:
[base][a][c] ?

I'm not sure I understand the question. What it seems to
boil down to is: is there any way, except the existing
way(s), to have a class [...]. This is what virtual
inheritance was designed for.

Not the existing ways, the ways that I know of. Other ways
besides the ways that I know of to do that. If virtual
inheritance is the only way then fine, I was just wondering.

Well, virtual inheritance is *the* way. It's doubtlessly
possible to simulate it using other techniques, but my point was
just: why? You know the "standard" solution, but it sounded
like you weren't too happy with it.
Thanks for everyone's help, think I understand it now. Are
there any pitfalls when using a lot of virtual inheritance?

There are pitfalls when any technique is used where it shouldn't
be. My own impression is that there are no more with virtual
inheritance than with normal inheritance, and that inheritance
really should have been virtual by default.
 

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

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,816
Latest member
SapanaCarpetStudio

Latest Threads

Top