Overloading functions

I was chatting with a friend of mine the other night, and I must confess, I was in a bit of bother about whether to blog this or not.  For a while now I’ve been aware that I take a lot of the language features of C++ for granted.  I know how to use an awful lot, but I don’t really get in to the guts of it. So while I know a lot of surface stuff, I don’t think the likes of Herb Sutter and Scott Meyers have anything to worry about just yet.

But as I was chatting with Craig, I was worried that what I was going to blog on would be career limiting, after all I’ve been coding in C++ for three years now, so surely I should know more right?  Well, as ever Craig had some very sage advice, so here goes.

I came across an interesting issue a few years back in a legacy system I was working on and at the time, I just ignored it as one of those things.  I’d been coding in C++ for a few months, and the developer in question told me, “don’t worry, I’ll fix it.”  And off he went, and I went on and did something else.

Now hands up who can tell me what mistake I made there?  That’s right, I should have asked the developer if I could pair program with him as he explained what the problem was and how to fix it if it ever happened again.

So the problem was there was a pair of overloaded functions, where one took a char* and the other took a string.  And this was causing some unexpected behaviour in the code.

So this struck me again as I was walking home from work one night, and I realised I never did find out what happens in that case.  So I decided to find out.  Albeit three years later.

So, let’s suppose we have the following code:

void printNum(int num) 
{
    cout << "Print num taking an int" << endl;
}

void printNum(double num)
{
    cout << "Print num taking a double" << endl;
}

 

And we call printNum and pass it a number like say 100.  How does the compiler know which version to call?  After all it could be either an int or a double.  Well, when I ran this code and passing it 100, it printed: “Print num taking an int.”  But why?

Well when faced with this, the compiler goes through an internal sequence to work out which one to call.

  1. It gets all the functions in the current scope that has the same name as the function we’re trying to call.  It ignores the ones that don’t have the same number of arguments.
  2. If there are no matches found, the compiler will return an error.
  3. If more than one is found, it selects the best match.
  4. If there’s no clear winner, then an ambiguous function call error is thrown by the compiler.

This looks quite simple, but how does the compiler then select the best match?  The compiler works on a ratings system for the way the types are passed in the call, and the competing lists match up in decreasing order of goodness.  The list is as follows.

  1. An exact match.
  2. A promotion, so for example if you have a function that takes an int, and you pass it a char, then the char is promoted to an int.
  3. A standard type conversion. So a conversion between a double and a float for example.
  4. A constructor or user defined conversions.

So in this instance, as we’ve passed the printNum an int, we’ll get the int version back, the same way if we passed it a double like say 46.5 we’ll get the double version back. 

But what if we have something like this?

void doSomething(char* something)
{
    cout << "Something with char*" << endl;
}

void doSomething(string something)
{
    cout << "Something with string" << endl;
}

And we call it thus: doSomething(“this is a test”);

Then what version does it call?  Well, for a start, the compiler gives me a warning when I compile this.  The warning is:

compilerError

So any bets on which one’s called when we run it?

runResult

It’s the char* one.  But why?  I’m not entirely sure yet, but from what I’ve read,  there is a default conversion rule to convert String literals to char *.  I am still looking in to this one, if I’m wrong then please please feel free to comment so I know.

So if we wanted the string version, then we’d need to cast our little test string to a string. 

Well hope all that helps, feel free to comment.

Happy coding.

Advertisements

About welshboy2008

In my spare time, I read, listen to music, play my guitar among other stuff. I love to write computer programs too. In various languages. But mostly C# and Java. I'm currently learning: PHP, Javascript, XML, ASP.NET, Python, C and Assembler.

Posted on 31/01/2015, in learning and tagged , , , . Bookmark the permalink. 2 Comments.

  1. When you have a constant in your code as you did in your examples the compiler gives it a default type. 100 is an signed int and “This is a test” is a const char*. This is the type that it is using to compare with the available options.

    You might want to have a look at http://www.cplusplus.com/doc/tutorial/constants/ for more information about literals to see how you can tell the compiler what type you want something to have.

    The reason you got a warning was that implicit casting from a const char* to a char* is a deprecated feature. It was not trying to cast from a std::string to a char* although I think the warning is potentially misleading.

    Also http://stackoverflow.com/questions/4949254/const-char-const-versus-const-char is a good explanation of const and pointers.

    Hope this helps

    • welshboy2008

      Thanks for commenting Steve, sorry I’ve not responded before now. Your comment was very helpful.

      Welshboy

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: