Multiple Inheritance ambiguity but not really?

Discussion in 'C++' started by Nick Overdijk, Apr 10, 2009.

  1. 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,
    Nick Overdijk, Apr 10, 2009
    #1
    1. Advertising

  2. Nick Overdijk wrote:
    > 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?
    Nick Overdijk, Apr 10, 2009
    #2
    1. Advertising

  3. Pete Becker wrote:
    > On 2009-04-10 18:54:20 -0400, Nick Overdijk <> 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!
    Nick Overdijk, Apr 11, 2009
    #3
  4. blargg wrote:
    > 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] ?
    Nick Overdijk, Apr 11, 2009
    #4
  5. Nick Overdijk

    James Kanze Guest

    On Apr 11, 2:16 am, Nick Overdijk <> wrote:
    > blargg wrote:
    > > 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:
    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
    James Kanze, Apr 11, 2009
    #5
  6. James Kanze wrote:
    > On Apr 11, 2:16 am, Nick Overdijk <> wrote:
    >> blargg wrote:
    >>> 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:
    > 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?
    Nick Overdijk, Apr 11, 2009
    #6
  7. Nick Overdijk

    James Kanze Guest

    On Apr 11, 4:13 pm, Nick Overdijk <> wrote:
    > James Kanze wrote:
    > >> 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.

    --
    James Kanze (GABI Software) email:
    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
    James Kanze, Apr 12, 2009
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. nc
    Replies:
    1
    Views:
    491
    nice.guy.nige
    Feb 3, 2005
  2. =?ISO-8859-1?Q?IvD=B2?=

    Multiple Inheritance Ambiguity

    =?ISO-8859-1?Q?IvD=B2?=, Jan 13, 2005, in forum: C++
    Replies:
    5
    Views:
    503
    John Carson
    Jan 14, 2005
  3. Daniel Mitchell

    Multiple inheritance ambiguity

    Daniel Mitchell, May 25, 2006, in forum: C++
    Replies:
    2
    Views:
    326
    mlimber
    May 25, 2006
  4. Adam Nielsen
    Replies:
    3
    Views:
    409
    Adam Nielsen
    Sep 27, 2007
  5. PuzzledwithC++

    multiple inheritance ambiguity question

    PuzzledwithC++, Oct 1, 2009, in forum: C++
    Replies:
    15
    Views:
    607
    Francesco S. Carta
    Oct 12, 2009
Loading...

Share This Page