Path: utzoo!utgpu!watserv1!watmath!att!dptg!ulysses!andante!alice!shopiro From: shopiro@alice.att.com (Jonathan Shopiro) Newsgroups: comp.lang.c++ Subject: Re: Faulty Ambiguity Detection with Virtual Bases Summary: ambiguity error arises because the vtbl is undefined Message-ID: <11558@alice.att.com> Date: 30 Oct 90 16:25:20 GMT References: <54733@brunix.UUCP> Organization: AT&T Bell Laboratories, Murray Hill NJ Lines: 87 In article <54733@brunix.UUCP>, sdm@cs.brown.edu (Scott Meyers) writes: > Normally, C++ doesn't complain about potential ambituity, only ambiguity at > a point of call. With MI, for example, if a function is inherited through > two paths, the function to be called must normally be disambiguated only > when it is called. As the ARM puts it (p. 206): > > Only the *use* of a name in an ambiguous way is an error, however; > combining classes that contain members with the same name in an > inheritance scheme is not an error. > > But consider the following example, where function foo is inherited through > two paths in class Bottom: > > class VBase { > public: > virtual void foo() = 0; > }; > > class Middle1: virtual public VBase { > public: > virtual void foo(); > }; > > class Middle2: virtual public VBase { > public: > virtual void foo(); > }; > > class Bottom: public Middle1, public Middle2 { > }; > > AT&T cfront 2.0 and Sun's cfront 2.1 (beta) both give the following error: > > "ambiguity.C", line 16: error: virtual base: ambiguous Middle1::foo() > and Middle2::foo() The problem here is that the vtbl can't be constructed. Suppose you had the code VBase* vbp = new Bottom; // pointer conversion vbp->foo(); // virtual function call Now the function call must be ambiguous, because you don't know whether to call Middle1::foo() or Middle2::foo(). But there is no way that the compiler can object to the call itself, because it can't know that vbp actually points to an instance of Bottom. So the error must be generated at the point of declaration. > On the other hand, g++ 1.37 takes it without complaining. But what function gets called? If it's either Middle1::foo() or Middle2::foo() I'd call that a bug in g++ 1.37. > Furthermore, if > either Middle1 or Middle2 is made a nonvirtual base class, then cfront is > happy, too, even though the ambiguity remains. No, actually the declarations are now okay, but the pointer conversion above becomes ambiguous, because there are now two instances of VBase hidden inside a Bottom object. You could write (note in the following at least one of Middle[12] is _not_virtually_derived_ from VBase): Bottom* bp = new Bottom; Middle1* m1p = new Bottom; Middle2* m2p = new Bottom; VBase* vbp; bp->foo(); // error: ambiguous call vbp = bp; // error: two instances of VBase vbp = m1p; vbp->foo(); // calls Middle1::foo() vbp = m2p; vbp->foo(); // calls Middle2::foo() > 1. Does anybody feel this is not an error in cfront? Apparently yes. > 2. Can anybody explain to me why it should make a difference whether a > base class is virtual or not in the above example? I hope the above helps. -- Jonathan E. Shopiro AT&T Bell Laboratories, Warren, NJ 07059-0908 shopiro@research.att.com (201) 580-4229