Overloading
I'm not sure what overloading is, but I hope it's making the machine do so much MORE than it should that smoke comes out!!!
Not quite.
I'm worried that smoke will come out of my ears!
It'll be fine.
Overloading is the idea that we can have more than one function with the same name.
What!! That seems super confusing! How would it know which one to use?!
When we define multiple functions with the same name, C++ uses the types of the arguments (and only the types) to figure out which function to call.
So, for example, if we had these two functions:
int combine(double x, double y) {
return (x+y)/2;
}
and
std::string combine(std::string x, std::string y) {
x.append(" & ");
x.append(y);
return x;
}
We could write
cout << combine(3.142, 2.718) << endl
cout << combine("Chalk", "Cheese") << endl
and C++ will call the right function!
Whoa, that's cool. It's like, “Go fetch the right function!”.
Okay, sure, but why? Why not just have distinct names, like
combineDoubles()
andcombineStrings()
?That's what C would do. And lots of other languages, too.
Those longer names do look a bit clumsy.
Indeed. And allowing multiple functions with the same name avoids issues with not being able to use a name because someone else has already used it for some other, totally unrelated, thing.
Hold your horses! What if I said
combine(1, 2)
, which doesn't match either of those, and I hadn't written acombine()
for integers?If there isn't a perfect match, C++ will perform promotions or conversions to try to find a suitable function.
Rules for Resolving Overloading
C++ finds the right function using the number of arguments and their types.
- If there is a perfect match, it's found the right function and is done.
- Otherwise, it produces a list of candidates based on the conversions/promotions it could perform.
- If, out of that list of candidates, there is an overloaded function that is
- Better than all the others for some arguments (i.e., fewer conversions); and,
- No worse than any of the others for the remaining arguments, then
- That function is the one that is used.
- Otherwise, the best choice is still ambiguous, and the compiler throws an error.
In our example, if we wrote combine(1,2)
, there is only one candidate that matches—the combine()
for double
s—and so it wins.
Will you test us on these rules?
Meh. That's my question, Hedgehog.
We expect you to understand the general idea, but we won't give you some complex case and have you work out candidates and which one wins.
Oh, thank goodness!
Overloading Operators
The cool thing is, not only can we overload functions, we can also introduce new incarnations of C++'s existing operators, such as +
, /
, =
, ++
and *
.
We've been doing that. We already did
operator=
andoperator<<
.Yes, but you may not really have thought about what was going on until now.
You've written lines like
cout << 42 << 'x' << 3.14;
but there's actually a bunch of work being done “behind the scenes” to make that simple print command work. Now, with everything you've learned in today's lesson, we can actually break it down.
That code is equivalent to
((cout << 42) << 'x') << 3.14;
which is, in turn, equivalent to
{
std::ostream& _temp1 = cout << 42;
std::ostream& _temp2 = _temp1 << 'x';
_temp2 << 3.14;
}
By convention, all these <<
operators return a reference to their left-hand argument, so our code is also equivalent to saying
cout << 42; // calls operator<<(std::ostream, int)
cout << 'x'; // calls operator<<(std::ostream, char)
cout << 3.14; // calls operator<<(std::ostream, double)
Now you can see how our (apparently) simple “print three values” code was actually calling three different functions.
Cool!
What's nice about this mechanism is that it's extensible. For example, if we define
operator<<
for our own types, we can print them just as easily as we can with C++'s built-in types.
That extensibility is a key principle. In C++ you can create your own classes that behave exactly like types that are built into the language. You can even overload the subscript operator, []
, and the function-call operator, ()
, to make objects that are array-like or function-like.
(When logged in, completion status appears here.)