Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does C++ pick which overloaded function to call?

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?

like image 820
Claudiu Avatar asked Dec 22 '08 04:12

Claudiu


4 Answers

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;
like image 184
Adam Rosenfield Avatar answered Nov 05 '22 14:11

Adam Rosenfield


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)
like image 27
Paige Ruten Avatar answered Nov 05 '22 14:11

Paige Ruten


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.

like image 3
Johannes Schaub - litb Avatar answered Nov 05 '22 15:11

Johannes Schaub - litb


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

like image 2
Robert Gould Avatar answered Nov 05 '22 13:11

Robert Gould