# Class 19: Functions IV

Section 4.6 of Problem Solving with C++

Lecture

Most of this lecture involves function overloading. This concept/feature may not seem too important right now, but as we progress in our understanding of programming and in our knowledge of C++, the importance of overloading will become more apparent. When you look at templates in higher level classes, it will be more and more apparent. We're talking about it now, because it should help you understand the role of types in C++ even better, and why I say that understanding types is one of the most important things you can get out of this class!

## Implicit type conversion and function calls

Consider the following bit of review. Suppose I have a function with prototype: `void rep(char,int);`, and with the following definition:

`void rep(char c, int k)`
`{`
`  for(int i = 0; i < k; i++)`
`    cout << c;`
`}`
`    `
 Code Resulting Output Explanation `char g = '%';``int  x = 10;``rep(g,x);` `%%%%%%%%%%` Clear from the function definition. `int  x = 10, y = 42;``rep(y,x);` `**********` `rep` expects a `char` as its first argument, but the first argument in the function call, `y`, is an `int`. Thus, `y` gets converted to a `char` to match the prototype, and the `char` interpretation of 42 (as we see from the ASCII table) is `'*'`. `int  x = 10;``double z = 42.553;``rep(z,x);` `**********` `rep` expects a `char` as its first argument, but the first argument in the function call, `z`, is a `double`. Thus, `z` gets converted to a `char` to match the prototype, and the `char` interpretation of 42.553 is ASCII value 42, which is `'*'`.

Now, what if I add another prototype and definition for the function `rep`, but with different types of arguments? For example, what if I have the following program

 Prototypes Definitions main `void rep(char,int);``void rep(int,int);` `void rep(char c, int k)``{``  for(int i = 0; i < k; i++)``    cout << c;``}``void rep(int n, int k);``{``  for(int i = 0; i < k; i++)``    cout << n;``}` `int main()``{``  int a = 55, b = 6;``  char c = 'X';`` ``  rep(c,b);  Alternative One`` ``  rep(a,b);  Alternative Two`` ``  return 0;``}`

What happens here? Well, Alternative One causes 6 `X`’s to be printed, and Alternative Two causes

`555555555555`

... to be printed. Why the difference? Which function gets used? Well, in Alternative One we used an object of type `char` as the first argument, so it used the version of `rep` with an object of type `char` as a first argument. In Alternative Two we used an object of type `int` as the first argument, so it used the version of `rep` with an object of type `int` as a first argument. This is called overloading of function names. The idea is, that the name of a function isn't just `rep`, the name of the function is really `rep(``int,int``)` or `rep(char,int)`. So:

Overloading of a function name occurs when two or more definitions are given for functions with the same name, but different number or types of arguments.

Note: the return type of a function is not considered in function overloading. Thus, it is illegal to have two functions whose prototype differs only in the return type. For example: `double f(int);` and `char f(int);` cannot coexist!

 Definition 1 Definition 2 Discussion `int max(int a, int b)``{``  if (a >= b)``    return a;``  else``    return b;``}` `int max(int a, int b, int c)``{``  return max(max(a,b),c);``}` No conflict here, because I can look at the number of arguments and decide which function to call `void mystery(int k, char c)``{``  for(int i = 0 i < k; i++)``  {``    for(int j = 0; j < k; j++)``      cout << c;``    cout << endl;``  }``}` `char mystery(char c, int k)``{``  return ((c - 'A' + k) % 26) + 'A';``}` No mystery here! If you see a call like `mystery(``'X',13)` you'd know that `mystery(char,int)` (i.e. the second definition) would be called. You just figure out which prototype matches.

When you make a function call with arguments whose types and number do not match any prototype, the compiler will try to use implicit type conversion to match a prototype. This is pretty straightforward (remember the example at the top of the page?) when function name overloading is not used. With oveloading, however, things can get complicated. For example:

 Definition 1 Definition 2 Function Call Discussion `void rep(char c, int k)``{``  for(int i = 0; i < k; i++)``    cout << c;``}` `void rep(int n, int k);``{``  for(int i = 0; i < k; i++)``    cout << n;``}` `rep(42.23,10);` Error! This function call is ambiguous! The compiler has no way of knowing whether the `double` 42.23 is supposed to be implicitly converted to the `char` `'*'` (an asterisk) so we can use `void rep(char,int)`, or whether it should be implicitly converted to the `int` 42 so we can use `void rep(int,int)`. This results in a compiler error!

How is the compiler supposed to decide which implicit conversion is best? When ambiguities like this arise, simply use explicit conversion to disambiguate. For the previous example, I might change the call `rep(``42.23,10);` to `rep(char(42.23),10);`, thus removing any ambiguity.

## A Common Use

One common use of overloading would go something like this: I've defined the function ```void rep(char c, int k, ostream& OUT);```, which writes the character `c` `k` times to the output stream `OUT`. This allows me to write to any output stream, of course, but I typically only want to write to the screen, and I don't like writing `rep('\$',30,cout)`, because I am evidently quite lazy, and instead I'd rather write `rep('\$',30)` with the understanding that if no output stream is specified, `rep` should write to `cout`. One way to accomplish this is to simply overload `rep` by adding this function definition:

`void rep(char c, int k)`
`{`
`  rep(c,k,cout);`
`}`

With this definition, I have my wish. It probably looks strange to have the function `rep` calling the function `rep`, but remember --- really we have the function `rep(``char,int``)` calling the function `rep(char,int,ostream&)`. Here (this program) is a complete program; when running it  the call `rep('\$',30)` actually results in calls to both `rep` functions.

## Recursion

Let's consider the following function, which is a variation on our old familiar example: A function `line(``int`` k)` that prints a line of `k` asterisks. And just to be on the safe side, let's make sure our function still works properly when negative `k`'s are passed to it. "Works properly" in this case means, does nothing!

`void line(int k)`
`{`
`  // Takes care of bad arguments!`
`  if (k < 0)`
`    return;`
` `
`  // Takes care of everything else!`
`  for(int i = 0; i < k; i++)`
`    cout << '*';`
`  cout << endl;`
`}`
`    `

If you call this function with an argument like 35, you get:

`***********************************`

Now, suppose I want to modify this so that it prints a second line below of length `k-1`, so that calling this function with an argument like 35 would give me

`***********************************`
`**********************************`

Well, I might decide to try the following idea. Since `line` already does all the work of printing out a line for me, why don't I just add a `line(``k-1)` at the end of my function definition? In other words, how aobut:

`void line(int k)`
`{`
`  // Takes care of bad arguments!`
`  if (k < 0)`
`    return;`
` `
`  // Takes care of everything else!`
`  for(int i = 0; i < k; i++)`
`    cout << '*';`
`  cout << endl;`
` `
`  // Print next line?`
`  line(k-1);`
`}`
`    `

Well, if I compile and run this with something like `line(``10)`, here's what I get:

`**********`
`*********`
`********`
`*******`
`******`
`*****`
`****`
`***`
`**`
`*`

So what happened? A function that "calls itself" as this one does is called recursive,. In class we’ll discuss this, and more on recursion is coming in the next lecture. You can also try changing around this program (try adding various cout statements) to see what happens when it runs.

## Problems

1.     Look at this program and explain what happens, i.e. answer the question posed up in the comment block.

2.     Look at this program, similar to the one above, and explain what happens, i.e. answer the question posed up in the comment block.

3.     Look at and/or run this program and figure out what useful work (if any) the mystery function accomplishes.