Thread: Ambiguity issue

  1. #1
    Registered User
    Join Date
    May 2006
    Posts
    1,579

    Ambiguity issue

    Hello everyone,


    I think compiler is too strict in this case. You can see, no data member, no virtual function.

    I am using Visual Studio 2008. The compiler error is simply because of Diamond pattern -- duplicate base class? Actually from logical point of view, there should be no ambiguity issue.

    Any ideas?

    Code:
    #include <iostream>
    
    using namespace std;
    
    class Base {
    public:
    	int foo() {cout << "Base" << endl;}
    };
    
    class Derived1: public Base
    {
    public:
    	int foo() {cout << "Derived1" << endl;}
    };
    
    class Derived2: public Base
    {
    public:
    	int foo() {cout << "Derived2" << endl;}
    };
    
    class Final: public Derived1, public Derived2 {
    public:
    	int foo() {cout << "Final" << endl;}
    };
    
    int main()
    {
    	Final f;
    	Final* p = &f;
    	Base* pb = p; //error C2594: 'initializing' : ambiguous conversions from 'Final *' to 'Base *'
    	return 0;
    }

    thanks in advance,
    George

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I am using Visual Studio 2008.
    Your code example fails to compile with the online Comeau compiler as well.

    The compiler error is simply because of Diamond pattern -- duplicate base class?
    Yes.

    Actually from logical point of view, there should be no ambiguity issue.
    Yes, but nonetheless there is ambiguity since with non-virtual inheritance there are two distinct Base sub-objects.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks laserlight,


    Quote Originally Posted by laserlight View Post
    Yes, but nonetheless there is ambiguity since with non-virtual inheritance there are two distinct Base sub-objects.
    Why "two distinct Base sub-objects"? I think object instances' different because of data member, common in code (member methods). Since there is no data members, I think they should be no differences. And they should not consume any space -- only data member consumes space and member functions share common code.


    regards,
    George

  4. #4
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    It sounds to me like you're thinking of virtual inherritance, which is not what your code snippet uses.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  5. #5
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    The language rules of C++ require that there be two distinct Base objects, whether they have data members or not. Furthermore, the language rules require that these two objects have different addresses. Thus, which subobject is cast to very much matters - you get different addresses. Try it out.

    Finally, the two objects actually do differ. One points to the "Final through Derived1" vtable, the other to the "Final through Derived2" vtable. This is important if you static_cast the Base pointer to Derived1 or 2, which you're allowed to do (only the correct one) under the C++ rules, if not under COM rules (but the compiler can't know you're doing COM).
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  6. #6
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks CornedBee,


    Two more comments,

    1.

    Quote Originally Posted by CornedBee View Post
    The language rules of C++ require that there be two distinct Base objects, whether they have data members or not. Furthermore, the language rules require that these two objects have different addresses. Thus, which subobject is cast to very much matters - you get different addresses. Try it out.
    I have tried they have different address. What makes me confused is sizeof (Base type object) will consume 1 byte. What is the 1 byte for?

    I think for a class object instance, only data member should consume memory (address), but in Base, there is no data member, and should not consume any address? But an object instance without taking any memory (address) sounds unbeliveable.

    2.

    Quote Originally Posted by CornedBee View Post
    Finally, the two objects actually do differ. One points to the "Final through Derived1" vtable, the other to the "Final through Derived2" vtable. This is important if you static_cast the Base pointer to Derived1 or 2, which you're allowed to do (only the correct one) under the C++ rules, if not under COM rules (but the compiler can't know you're doing COM).
    There is no virtual function in my sample class, Base, Derived1, Derived2 and Final. Why do you say there is still a vtable (I think you mean virtual function table)? From debugger, you can not see a _vfptr there.


    regards,
    George

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I have tried they have different address. What makes me confused is sizeof (Base type object) will consume 1 byte. What is the 1 byte for?

    I think for a class object instance, only data member should consume memory (address), but in Base, there is no data member, and should not consume any address? But an object instance without taking any memory (address) sounds unbeliveable.
    Read Stroustrup's FAQ: Why is the size of an empty class not zero?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks laserlight,


    Any comments to my point (2) in post #6? :-)

    Quote Originally Posted by laserlight View Post

    regards,
    George

  9. #9
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Whether the functions are virtual or not, there are two distinct versions of "base" that could be the base pointer you'd convert to - and that's what the compiler is complaining about. There may not be a vtable, but the compiler would have to know WHICH one of the two base objects you mean in the statement to resolve any references to the pointer later on - and this is why it's refusing.

    But most importantly: Multiple inheritance is something that is best avoided, particularly if the same base is involved more than once. Just don't do that.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  10. #10
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Quote Originally Posted by George2 View Post
    There is no virtual function in my sample class, Base, Derived1, Derived2 and Final. Why do you say there is still a vtable (I think you mean virtual function table)? From debugger, you can not see a _vfptr there.
    Basically, the problem is that you create too many threads, so I confused some of them.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  11. #11
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks CornedBee,


    This is what you mentioned is post #5,

    --------------------
    if not under COM rules (but the compiler can't know you're doing COM).
    --------------------

    Why use static_cast to cast Base to Derved1 or Derived2 violates COM programming princlple?

    Thanks Mats,

    This is what CornedBee mentioned in post #5

    --------------------
    Finally, the two objects actually do differ. One points to the "Final through Derived1" vtable, the other to the "Final through Derived2" vtable. This is important if you static_cast the Base pointer to Derived1 or 2, which you're allowed to do (only the correct one) under the C++ rules, if not under COM rules (but the compiler can't know you're doing COM).
    --------------------

    This is what I said in post #6
    --------------------
    There is no virtual function in my sample class, Base, Derived1, Derived2 and Final. Why do you say there is still a vtable (I think you mean virtual function table)? From debugger, you can not see a _vfptr there.
    --------------------

    So, there should not be any reserved vtable or vtable pointer data structure in a class's instance, whose class does not have virtual function at all, right?

    Quote Originally Posted by matsp View Post
    Whether the functions are virtual or not, there are two distinct versions of "base" that could be the base pointer you'd convert to - and that's what the compiler is complaining about. There may not be a vtable, but the compiler would have to know WHICH one of the two base objects you mean in the statement to resolve any references to the pointer later on - and this is why it's refusing.

    But most importantly: Multiple inheritance is something that is best avoided, particularly if the same base is involved more than once. Just don't do that.

    --
    Mats

    regards,
    George
    Last edited by George2; 02-08-2008 at 02:47 AM.

  12. #12
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Why use static_cast to cast Base to Derved1 or Derived2 violates COM programming princlple?
    You're not allowed to cast in COM, except for downcasts (derived->base). You have to use QueryInterface for everything beyond that.

    So, there should not be any reserved vtable or vtable pointer data structure in a class's instance, whose class does not have virtual function at all, right?
    Correct. I just assumed that there was a virtual function, because this thread was such a clear derivative of the thread where you asked about the cast in the COM object implementation.

    However, this doesn't change the fact that the standard requires that
    1) every object has non-zero size (i.e. sizeof(EmptyClass) > 0) and
    2) no two objects of the same type reside at the same address.

    In particular, the latter applies to same-type base objects of any given class, too. The Base coming through the Derived1 path may not sit at the same address as the Base coming through the Derived2 path.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  13. #13
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Rephrasing CornedBee's statement to make it clearer.
    The Base coming through the Derived1 path can not sit at the same address as the Base coming through the Derived2 path.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  14. #14
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks CornedBee,


    Your reply is great! I have programmed with COM for some time. Actually, I have never seen cast other than downcast. Why in COM we should not upcast anything?

    Quote Originally Posted by CornedBee View Post
    You're not allowed to cast in COM, except for downcasts (derived->base). You have to use QueryInterface for everything beyond that.

    regards,
    George

  15. #15
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Because the cast relies on knowledge you're not supposed to have.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. float calculation issue
    By George2 in forum C# Programming
    Replies: 1
    Last Post: 05-26-2008, 04:56 AM
  2. type safe issue
    By George2 in forum C++ Programming
    Replies: 4
    Last Post: 02-12-2008, 09:32 PM
  3. Ambiguity error with double as parameter type
    By tejasvsrinivasa in forum C++ Programming
    Replies: 2
    Last Post: 11-11-2007, 04:17 PM
  4. directsound issue
    By valis in forum Tech Board
    Replies: 0
    Last Post: 06-25-2006, 09:28 PM
  5. my first issue of GDM
    By DavidP in forum A Brief History of Cprogramming.com
    Replies: 0
    Last Post: 09-12-2002, 04:02 PM