Multiple Inheritance: Ambiguous Function

Please support our C++ advertiser: Intel Parallel Studio Home
Thread Solved

Join Date: May 2008
Posts: 376
Reputation: Clockowl is on a distinguished road 
Solved Threads: 27
Clockowl's Avatar
Clockowl Clockowl is offline Offline
Posting Whiz

Multiple Inheritance: Ambiguous Function

 
1
  #1
Apr 10th, 2009
Hey guys,

I was wondering, with this code:

main.cpp
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. class car {
  5. public:
  6. car (float speed) :
  7. speed(speed) {}
  8.  
  9. car () :
  10. speed(0) {}
  11.  
  12. void cruise(float speed) {
  13. this->speed = speed;
  14. cout << "New speed: " << getSpeed() << endl;
  15. }
  16.  
  17. void brake(float power) {
  18. this->speed -= power*power/4;
  19. }
  20.  
  21. float getSpeed() {
  22. return speed;
  23. }
  24.  
  25. private:
  26. float speed;
  27. };
  28.  
  29. class racer : public car {
  30. public:
  31. void boost(float power) {
  32. cout << "BOOST! ";
  33. cruise(getSpeed() + power*power/3);
  34. }
  35. };
  36.  
  37. class tank : public car {
  38. public:
  39. bool shoot(float aimTime) {
  40. cout << "Shot ";
  41. if (aimTime > 5.0) {
  42. cout << "hits!" << endl;
  43. return true; //hit!
  44. } else {
  45. cout << "misses!" << endl;
  46. return false; //miss!
  47. }
  48. }
  49.  
  50. };
  51.  
  52. class racetank : public racer, public tank {
  53. public:
  54. bool boostShoot(float power, float aimTime) {
  55. boost(power*2);
  56. return shoot(aimTime*2);
  57. }
  58. };
  59.  
  60. int main() {
  61. racetank mycar;
  62. mycar.car::cruise(50);
  63. mycar.boost(20);
  64. mycar.car::brake(5);
  65. mycar.boostShoot(35, 1.4);
  66.  
  67. return 0;
  68. }

MinGW's GCC gives me these errors:
  1. D:\MyDocs\Code\InheritThis\main.cpp||In function `int main()':|
  2. D:\MyDocs\Code\InheritThis\main.cpp|62|error: `car' is an ambiguous base of `racetank'|
  3. D:\MyDocs\Code\InheritThis\main.cpp|64|error: `car' is an ambiguous base of `racetank'|
  4.  

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?

Thanks in advance,

PS:
I know the solution to this is to use virtual inheritance, but I was wondering why C++ works like it does.
Reply With Quote Quick reply to this message  
Join Date: May 2008
Posts: 376
Reputation: Clockowl is on a distinguished road 
Solved Threads: 27
Clockowl's Avatar
Clockowl Clockowl is offline Offline
Posting Whiz

Re: Multiple Inheritance: Ambiguous Function

 
0
  #2
Apr 10th, 2009
Replying to myself yeey.

Let a class in memory be resembled by:

[classname]

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

class a;
class b : a;

class a looks like this:
[a]

b looks like this:
[a][b]

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][b]
c: [base][a][base][b][c]

c, more specific, looks like this:
[a::base][a][b::base][b][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?
Reply With Quote Quick reply to this message  
Join Date: Oct 2008
Posts: 476
Reputation: nucleon has a spectacular aura about nucleon has a spectacular aura about 
Solved Threads: 91
nucleon's Avatar
nucleon nucleon is offline Offline
Posting Pro in Training

Re: Multiple Inheritance: Ambiguous Function

 
0
  #3
Apr 10th, 2009
> How else can they be different?
Yep, they must be the same function.

It works if you pick a specific copy like this:
mycar.racer::cruise(50); or this
mycar.tank::cruise(50);
But "diamond inheritance" looks like something to avoid in general. Seems strange that the language wasn't designed to include only one copy in such a case.
Reply With Quote Quick reply to this message  
Join Date: May 2008
Posts: 376
Reputation: Clockowl is on a distinguished road 
Solved Threads: 27
Clockowl's Avatar
Clockowl Clockowl is offline Offline
Posting Whiz

Re: Multiple Inheritance: Ambiguous Function

 
0
  #4
Apr 10th, 2009
Quoting myself:
I know the solution to this is to use virtual inheritance, but I was wondering why C++ works like it does.

The correct solution is to virtual inherit the class cars in race and tank class. This way, the compiler creates only one car inside of racetank, and 2 vtables to be able to still call the functions.

Basically, I was just wondering why GCC doesn't just pick one of the functions and give me a warning instead of 2 errors.

--Edit, a bit later:

So the compiler asks me what this pointer to give to the function, that of class a or b? It doesn't matter if one only uses class c, but when one degrades class c to class a, b or base, the data members may have different values then what was expected if the compiler chose instead of the programmer. Say function modifies int value, how would the programmer know what value it was modified, that of a or b? Therefore a name must be presented if one wants to call functions like this.

The "proper" solution, in most cases, is to go by virtual inheritance.

This was helpful research. Multiple Virtual Inheritance seems a nice and powerful tool, albeit a bit tricky.
Last edited by Clockowl; Apr 10th, 2009 at 9:33 pm.
Reply With Quote Quick reply to this message  
Join Date: Mar 2009
Posts: 311
Reputation: NicAx64 will become famous soon enough NicAx64 will become famous soon enough 
Solved Threads: 19
NicAx64's Avatar
NicAx64 NicAx64 is offline Offline
Posting Whiz

Re: Multiple Inheritance: Ambiguous Function

 
0
  #5
Apr 10th, 2009
Basically, I was just wondering why GCC doesn't just pick one of the functions and give me a warning instead of 2 errors.
I have compiled your mentioned source by the microsoft C++ compiler too. the same error message is there.

  1. error C2385: 'racetank::car' is ambiguous

So it's not a compiler bug or compiler specific thing , it should be something that clearly defined on the C++ language specification.

Let this thread open may be later some expertise see this thread and reply.


The correct solution is to virtual inherit the class cars in race and tank class. This way, the compiler creates only one car inside of racetank, and 2 vtables to be able to still call the functions.
and using virtual doesn't slove this problem. I used the Microsoft C++ compiler.I think it's not the reason.

yes there is a correct solution for this ,, see this ,
http://msdn.microsoft.com/en-us/libr...2f(VS.71).aspx

anyway why this happen is not still clear. so please keep this
thread open.
Last edited by NicAx64; Apr 10th, 2009 at 9:42 pm.
Nothing like a kernel pannic !
Reply With Quote Quick reply to this message  
Join Date: Mar 2009
Posts: 311
Reputation: NicAx64 will become famous soon enough NicAx64 will become famous soon enough 
Solved Threads: 19
NicAx64's Avatar
NicAx64 NicAx64 is offline Offline
Posting Whiz

Re: Multiple Inheritance: Ambiguous Function

 
0
  #6
Apr 10th, 2009
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. class car {
  5. public:
  6. car (float speed) :
  7. speed(speed) {}
  8.  
  9. car () :
  10. speed(0) {}
  11.  
  12. void cruise(float speed) {
  13. this->speed = speed;
  14. cout << "New speed: " << getSpeed() << endl;
  15. }
  16.  
  17. void brake(float power) {
  18. this->speed -= power*power/4;
  19. }
  20.  
  21. float getSpeed() {
  22. return speed;
  23. }
  24.  
  25. private:
  26. float speed;
  27. };
  28.  
  29. class racer : public car {
  30. public:
  31. void boost(float power) {
  32. cout << "BOOST! ";
  33. cruise(getSpeed() + power*power/3);
  34. }
  35. };
  36.  
  37. class tank : public car {
  38. public:
  39. bool shoot(float aimTime) {
  40. cout << "Shot ";
  41. if (aimTime > 5.0) {
  42. cout << "hits!" << endl;
  43. return true; //hit!
  44. } else {
  45. cout << "misses!" << endl;
  46. return false; //miss!
  47. }
  48. }
  49.  
  50. };
  51.  
  52. class racetank : public racer, public tank {
  53. public:
  54.  
  55. using tank::cruise ;
  56. using racer::brake ;
  57. bool boostShoot(float power, float aimTime) {
  58. boost(power*2);
  59. return shoot(aimTime*2);
  60. }
  61. };
  62.  
  63. int main() {
  64.  
  65.  
  66. racetank mycar;
  67. mycar.cruise(50);
  68. mycar.boost(20);
  69. mycar.brake(5);
  70. mycar.boostShoot(35, 1.4);
  71.  
  72. return 0;
  73. }
This code compiles nicely , so this is the solution , but the problem is
still unclear.
Nothing like a kernel pannic !
Reply With Quote Quick reply to this message  
Join Date: May 2008
Posts: 376
Reputation: Clockowl is on a distinguished road 
Solved Threads: 27
Clockowl's Avatar
Clockowl Clockowl is offline Offline
Posting Whiz

Re: Multiple Inheritance: Ambiguous Function

 
0
  #7
Apr 10th, 2009
No, that's not the proper solution to this.

This is

  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4.  
  5. class car {
  6. public:
  7. car (float speed) :
  8. speed(speed) {}
  9.  
  10. car () :
  11. speed(0) {}
  12.  
  13. void cruise(float speed) {
  14. this->speed = speed;
  15. getSpeed(true);
  16. }
  17.  
  18. void brake(float power) {
  19. this->speed -= power*power/4;
  20. getSpeed(true);
  21. }
  22.  
  23. float getSpeed(bool verbose = false) {
  24. if (verbose) {
  25. cout << "New speed: " << getSpeed() << endl;
  26. }
  27. return speed;
  28. }
  29.  
  30. private:
  31. float speed;
  32. };
  33.  
  34. class racer : virtual public car {
  35. public:
  36. void boost(float power) {
  37. cout << "BOOST! ";
  38. cruise(getSpeed() + power*power/3);
  39. }
  40. };
  41.  
  42. class tank : virtual public car {
  43. public:
  44. bool shoot(float aimTime) {
  45. cout << "Shot ";
  46. if (aimTime > 5.0) {
  47. cout << "hits!" << endl;
  48. return true; //hit!
  49. } else {
  50. cout << "misses!" << endl;
  51. return false; //miss!
  52. }
  53. }
  54.  
  55. };
  56.  
  57. class racetank : public racer, public tank {
  58. public:
  59. bool boostShoot(float power, float aimTime) {
  60. boost(power*2);
  61. return shoot(aimTime*2);
  62. }
  63. };
  64.  
  65. int main() {
  66. racetank mycar;
  67. mycar.cruise(50);
  68. mycar.boost(20);
  69. mycar.brake(5);
  70. mycar.boostShoot(35, 1.4);
  71.  
  72. return 0;
  73.  
  74. return 0;
  75. }

This way, racetank only has one base object car, not two. Virtual Inheritance
Reply With Quote Quick reply to this message  
Join Date: Apr 2009
Posts: 15
Reputation: stumpy798 is an unknown quantity at this point 
Solved Threads: 5
stumpy798 stumpy798 is offline Offline
Newbie Poster

Re: Multiple Inheritance: Ambiguous Function

 
0
  #8
Apr 11th, 2009
....
Reply With Quote Quick reply to this message  
Reply

This thread has been marked solved.
Perhaps start a new thread instead?
Message:


Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC