C++ Multiple Inheritance Function Call Ambiguity

C++ multiple inheritance function call ambiguity

a.base1::start();

a.base2::start();

or if you want to use one specifically

class derived:public base1,public base2
{
public:
using base1::start;
};

Fixing C++ Multiple Inheritance Ambiguous Call

This is because of a diamond inheritance pattern, to resolve the error you can specify the specific namespace you want the member from like.

paddressType->MeasurementKeyword::GetValue()

or

paddressType->CharacterKeyword::GetValue()  

  1. Basically your AddressType class has access to the GetValue members from both the classes it inherits from and can't choose one (call is ambiguous).
  2. The scope resolution operator (:: ) helps specify which one you actually want.
  3. You haven't said what you actually want this code to do so I'll just say that generally complex inheritance patterns are not conducive to creating readable code, rethink what you actually want.

Multiple Inheritance: Ambiguous access to methods with different signature

This has to be a duplicate, but I can't find it.

Overloading applies to functions with the same name defined in the same scope. In the code in the question, the two functions are defined in different scopes, one in class A and one in class B, so they do not overload, and the compiler is not allowed to pick one or the other. So the call is ambiguous.

The way to resolve this is to tell the compiler which one you want. From outside it's ugly: test.B::SetValue("Test");, if I remember correctly.

The reason for this is maintainability. Suppose that the class A in the example came from a third-party library and did not have a function named SetValue. In the code in the question, test.SetValue("test") would be fine: it calls B::SetValue(std::string), converting the string literal into a std::string. Now you install a new version of that third-party library, and A now has a new member function, A::SetValue(const char*). If the compiler applied overload resolution to those two SetValue functions, it would call the new one, and the behavior of your previous code would change: it would call A::SetValue instead of B::SetValue. That makes code fragile.

Since there seems to be a lot of confusion here: this is not name hiding. The usual example of name hiding occurs when a base class defines a name, and a class derived from that base also defines a name. The one in the base is said to be hidden; formally, the compiler simply stops looking when it sees the one in the derived class. The same thing applies when a class defines a name that's the same as a name in global scope; the compiler doesn't look outside the class after it's found the name inside the class.

C++ multiple inheritance static function call ambiguity

Making "announce" protected in StaticBaseA and StaticBaseB might be part-way to doing what you want.

You then could not call StaticBaseB<NonDerived>::announce from main as it would be inaccessible. You could call it from a class derived from StaticBaseB.

In other words:

template<class TDerived>
class StaticBaseA
{
protected:
static void announce()
{
std::cout << "do something" << std::endl;
}
};

template<class TDerived>
class StaticBaseB
{
protected:
static void announce()
{
std::cout << "do something else" << std::endl;
}
};

In Derived you have to promote "announce" to public.

class Derived : public StaticA<Derived>, public StaticB<Derived >
{
public:
using StaticA<Derived>::announce;
};

int main()
{
Derived::announce(); // legal and calls StaticBaseA::announce
NotDerived::announce(); // no such function
StaticBaseA< Derived >::announce(); // not accessible
StaticBaseB< Derived >::announce(); // also not accessible
StaticBaseA< NotDerived >::announce(); // not accessible
StaticBaseB< NotDerived >::announce(); // also not accessible
}

Ambiguity in case of multiple inheritance and spaceship operator in C++20

gcc is correct here.

When you do:

c.operator<(c);

You are performing name lookup on something literally named operator<. There is only one such function (the one in A) so this succeeds.

But when you do c < c, you're not doing lookup for operator<. You're doing two things:

  1. a specific lookup for c < c which finds operator< candidates (member, non-member, or builtin)
  2. finding all rewritten candidates for c <=> c

Now, the first lookup succeeds and finds the same A::operator< as before. But the second lookup fails - because c <=> c is ambiguous (between the candidates in A and B). And the rule, from [class.member.lookup]/6 is:

The result of the search is the declaration set of S(N,T).
If it is an invalid set, the program is ill-formed.

We have an invalid set as the result of the search, so the program is ill-formed. It's not that we find nothing, it's that the whole lookup fails. Just because in this context we're looking up a rewritten candidate rather than a primary candidate doesn't matter, it's still a failed lookup.


And it's actually good that it fails because if we fix this ambiguous merge set issue in the usual way:

  struct C : A, B {
+ using A::operator<=>;
+ using B::operator<=>;
};

Then our lookup would be ambiguous! Because now our lookup for the rewritten candidates finds two operator<=>s, so we end up with three candidates:

  1. operator<(A const&, A const&)
  2. operator<=>(A const&, A const&)
  3. operator<=>(B const&, B const&)

1 is better than 2 (because a primary candidate is better than a rewritten candidate), but 1 vs 3 is ambiguous (neither is better than the other).

So the fact that the original fails, and this one also fails, is good: it's up to you as the class author to come up with the right thing to do - since it's not obvious what that is.

C++: Ambiguos function call even with unique function names at each inheritence level

I expected class Q to hide the print() function of class P

This has nothing to do with Q hiding the superclass's print().

Q2 inherits from P, and therefore inherits print().

class R: public Q2, public Q { };

print() is inherited from both Q2 and from Q. Whether they turn out to be the same or different methods is immaterial. The point is that it is ambigous which print() method R.print() resolves to.

would expect an ambiguous call error when Q2 has the same function name

But it does. It inherits it.

Ambiguous call when inheriting multiple times from generic base class

This code is ill-formed. If the operator() is not available in the derived class, then name lookup only considers the base class if there is exactly one base class. If there are multiple base classes, then none of the base classes are considered in name lookup.

As you've mentioned, you can copy the implementations of operator() into the derived class, and that works, but you can also bring both of the operator() names into the derived class with a using directive, like this:

class : public Translate<T1>, public Translate<T2> {
public:
using Translate<T1>::operator();
using Translate<T2>::operator();
} tr;

Here's a demo.



Related Topics



Leave a reply



Submit