How does C++ pick which overloaded function to call?
-
23-08-2019 - |
Question
Say I have three classes:
class X{};
class Y{};
class Both : public X, public Y {};
I mean to say I have two classes, and then a third class which extends both (multiple-inheritance).
Now say I have a function defined in another class:
void doIt(X *arg) { }
void doIt(Y *arg) { }
and I call this function with an instance of both:
doIt(new Both());
This causes a compile-time error, stating that the function call is ambiguous.
What are the cases, besides this one, where the C++ compiler decides the call is ambiguous and throws an error, if any? How does the compiler determine what these cases are?
Solution
Simple: if it's ambiguous, then the compiler gives you an error, forcing you to choose. In your snippet, you'll get a different error, because the type of new Both()
is a pointer to Both
, whereas both overloads of doIt()
accept their parameters by value (i.e. they do not accept pointers). If you changed doIt()
to take arguments of types X*
and Y*
respectively, the compiler would give you an error about the ambiguous function call.
If you want to explicitly call one or the other, you cast the arguments appropriately:
void doIt(X *arg) { }
void doIt(Y *arg) { }
Both *both = new Both;
doIt((X*)both); // calls doIt(X*)
doIt((Y*)both); // calls doIt(Y*)
delete both;
OTHER TIPS
I get this error with gcc:
jeremy@jeremy-desktop:~/Desktop$ g++ -o test test.cpp
test.cpp: In function ‘int main(int, char**)’:
test.cpp:18: error: call of overloaded ‘doIt(Both&)’ is ambiguous
test.cpp:7: note: candidates are: void doIt(X)
test.cpp:11: note: void doIt(Y)
This is a perfect example of using boost::implicit_cast
:
void doIt(X *arg) { }
void doIt(Y *arg) { }
doIt(boost::implicit_cast<X*>(new Both));
Unlike with other solutions (including static_cast), the cast will fail if no implicit conversion from Both*
to X*
is possible. This is done by a trick, best shown at a simple example:
X * implicit_conversion(X *b) { return b; }
That's what is boost::implicit_cast
, just that it is a template which tells it the type of b
.
The compiler does a depth-search, not a breadth-search for picking overloads. The full answer is in Herb Sutter's exceptional C++, unfortunately I don't have the book in hand.
Edit: Got the book at hand now It's called the depth first rule is called "The Interface Principle":
The Interface Principle For a class X, all functions, including free functions, that both (a) "mention" X, and (b) are "supplied with" X are logically part of X, because they form part of the interface of X.
but there is a secondary rule called the "Koenig Lookup", that makes things harder.
Quote:"(simplified): if you supply a function argument of class type (here x, of type A::X), then to look up the correct function name the compiler considers matching names in the namespace (here A) containing the argument's type" -Herb Sutter, Exceptional C++, p120
you need to explicitly cast your argument to either x or y
doIt(new Both());
so add...
(X *) or (Y *)
like...
doIt((X *)new Both());
AFAIK the C++ compiler will always pick the closest and most specific match that it can determine at compile time.
However, if your object is derived from both, I think that the compiler should give you an error or at least a very severe warning. Declaration order should not matter since this is about subtyping relations, and the first object is not "more of a subtype" than the other.