trying to learn to use an overloaded function

Rugoingwme
Rugoingwme used Ask the Experts™
on
Hi,

I'm trying to learn how to program in C++.  I have minimal experience programming, having had only one FORTRAN programming course 20 years ago.  I bought a book that teaches C++ programming, but this book didn't give an example of a program written to highlight overloaded functions.  I'm having to create a program using an overloaded function called average to find the average of 2 numbers using

int average(int, int)
long average(long, long)
float average(float, float)

I was trying to create a program to do this using numbers that a person could input, then the program would find the average. I seem to consistently find errors, and the program doesn't compile, or compiles, but gives the answer only in a couple of cases.  Any guidance is appreciated.  Thanks.

Here's the code:

#include <iostream>

int main()
{

      // calculating the average of two integers, two long integers
      // or 2 floating-point values using an overloaded function called average

      // define variables      

      int x, y;
      long a, b;
      float m, n;


      // try using if statements to put the inputs into the appropriate variable buckets, then do the
      // overloaded function thing.  
      
      // first function
      std::cout << "This program calculates the average of 2 numbers. \n";
      std::cout << "what is the first number you want to average? \n";
      std::cin >> x;

            if (x % == 0)
                  {
                  int average(int x, y);
                  std::cout << "what is the second number you want to average? \n";
                  std::cin >> y;
                  std::cout << (x + y) / 2;
                  return 0;      
                  }
            if (x > 4294967295)
                  {
                  a = x;
                  long average(long a, b);
                  std::cout << "what is the second number you want to average? \n";
                  std::cin >> b;
                  std::cout << (a + b) / 2;
                  return 0;      
                  }
            if (x > 1.2e-38)
                  {
                  m = x;
                  float average(float m, n);
                  std::cout << "what is the second number you want to average? \n";
                  std::cin >> n;
                  std::cout << (m + n) / 2;
                  return 0;      
                  }      

} averagef.cpp
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Dear,

Please find the code corrected.

Best Regards
#include <iostream>

int main()
{

	// calculating the average of two integers, two long integers
	// or 2 floating-point values using an overloaded function called average

	// define variables	

	int x, y;
	long a, b;
	float m, n;


	// try using if statements to put the inputs into the appropriate variable buckets, then do the 
	// overloaded function thing.  
	
	// first function
	std::cout << "This program calculates the average of 2 numbers. \n";
	std::cout << "what is the first number you want to average? \n";
	std::cin >> x;

		if (x == 0)
			{
			int average(int x, int y);
			std::cout << "what is the second number you want to average? \n";
			std::cin >> y;
			std::cout << (x + y) / 2;
			return 0;	
			}
		if (x > 4294967294UL)
			{
			a = x;
			long average(long a, long b);
			std::cout << "what is the second number you want to average? \n";
			std::cin >> b;
			std::cout << (a + b) / 2;
			return 0;	
			}
		if (x > 1.2e-38)
			{
			m = x;
			float average(float m,float n);
			std::cout << "what is the second number you want to average? \n";
			std::cin >> n;
			std::cout << (m + n) / 2;
			return 0;	
			}	

}

Open in new window

Top Expert 2016
Commented:
a few remarks to your code:

int and long type are for most nowadays compilers a signed 32-bit integer type. you could test that on your system by outputting sizeof(long) and sizeof(int) at begin of your main.

for that case overloading the average function doesn't make really sense. but also the average function with float type is not really necessary. floats normally are 32-bit floating point numbers with a decimal precision of 5 to 6 digits what normally is too bad for even simple arithmetics. floats were used in the past where you need to spare any byte what rarely is the case nowadays. so i would recommend to forget the float type and use double instead.  

regarding the average function you should see that an average function that returns int or long is mathematical incorrect for most cases as the result is not an integer. so average funcion should return double type for all overloads. but if doing so, overloading of average function with integer input would be not needed cause double would take both int and long such that one average function with double type would be competely sufficient.

the next issue in your code is that you only declared the functions but neither implemented them nor called them.

double average(double d1, double d2)
{
    return (d1+d2)/2.;
}

Open in new window


the above implements average function for double type. you could add overloads taking int or long type. but as told it makes nor really sense cause all would return the same and you would get errors when calling for example

double d = average(1., 2);

Open in new window

here the compiler would say the statement is ambigious cause it could use the average function taking int arguments or that taking doubles.

so generally function overloads should return same type and you better avoid overloads where could be covered by another overload as well.

last thing: for polymorphism with different types, template function normally is better approach than providing multiple overloads:

template<typename T, typename R> void average(T t1, T t2, R& r);

Open in new window


i added the return type to the arguments as output argument cause that way the compiler can deduce the types T and R automatically and statements like

double d; average(1., 2, d);

Open in new window



would compile and work properly.  

Sara

Robert SchuttSoftware Engineer
Commented:
Templating is very nice, but it's a very advanced solution. I think step 1 is to explain overloading by using the function prototypes given at the start of the question. I don't have a good working environment so sorry for the crappy code below but it does show how the overloaded function calls work in this stage of learning the language. In determining the input type you could try your old way or a nicer way with error trapping maybe.

#include <iostream>

int average(int, int);
long average(long, long);
float average(float, float);

int main()
{
      // calculating the average of two integers, two long integers
      // or 2 floating-point values using an overloaded function called average

      // define variables

      int x, y;
      long a, b;
      float m, n;

      char inputstring[255];
      int t; // type indicator

      std::cout << "This program calculates the average of 2 numbers. \n";
      std::cout << "what is the first number you want to average? \n";
      std::cin >> inputstring;
      if (sscanf(inputstring, "%f\n", &m) == 1)
          t = 3; // float
      if (sscanf(inputstring, "%ld\n", &a) == 1)
          t = 2; // long int
      if (sscanf(inputstring, "%d\n", &x) == 1)
          t = 1; // int
      std::cout << "what is the second number you want to average? \n";
      std::cin >> inputstring;
      switch (t) {
         case 1:
            sscanf(inputstring, "%d\n", &y);
            printf("%d\n", average(x, y));
            break;
         case 2:
            sscanf(inputstring, "%ld\n", &b);
            printf("%ld\n", average(a, b));
            break;
         case 3:
            sscanf(inputstring, "%f\n", &n);
            printf("%f\n", average(m, n));
            break;
      }
      return 0;
}

int average(int num1, int num2)
{
    std::cout << "average being called for integers\n";
    return (num1 + num2) / 2;
}

long average(long num1, long num2)
{
    std::cout << "average being called for longs\n";
    return (num1 + num2) / 2;
}

float average(float num1, float num2)
{
    std::cout << "average being called for floats\n";
    return (num1 + num2) / 2;
}

Open in new window

Author

Commented:
Hi everyone,
I divided up the points the way i did because:
Madshiva: I understand the code changes you made.  I still don't really understand overloaded functions better, but you fixed my code.

sarabande: your comment about me declaring the functions, but not implementing them or calling them was helpful.  Unfortunately, most of your other explanations went over my head.  I do recall saying clearly that I was a beginner, but I should have said that i'm only about 5 chapters into a 24 chapter book to teach C++, so that's my bad.

robert_schutt: I think I understand conceptually what you did, but you used statements like "inputstring", "sscanf", and "switch", which I don't yet understand.  I tried compiling the code you wrote, and I couldn't get it to compile.
Top Expert 2016

Commented:
my bad. i try in simpler words:

the average of two numbers isn't a good sample for overloading as you don't have a difference in the method and in result when using different argument types. that means the average of 1 and 2 will be computed exactly with the same statements than that of 123.45 and 98.765 and it makes not so much sense to provide two functions cause it is always the sum of the arguments divided by two. if you return an int or a long type, it is also a mathematical flaw cause the average of 1 and 2 is 1.5 and not 1 (what would be the result of your function).

therefore in c++ the average would be good for templating where the same statements can be used and only the argument type is a variable. i didn't show the template code as a solution but only for demonstration that in c++ there are further polymorphism concepts beside overloading.

the code MadShiva posted doesn't 'repair' anything, beside that it may compile:

- there are still no implementations for the functions
- there is still no call but only a repetition of the declaration already done above main

so it really couldn't help you.

the code of Robert Schutt adds both the calls and the implemented functions and if you would build it (i think you only would need to add the statement 'using namespace std;' and it would build )  and run, you will see that it correctly runs the correct overload when you enter a float.

for integer input i would assume it always runs the int version of the overloaded functions cause for most compilers int and long are equivalent 32-bit integer types. so, the sscanf would return 1 (TRUE) for both integer formats %ld and %d if you enter an integer less than 2^31  (cause int and long are signed integers and the highest bit (of the 32) was used for sign. and both calls would return 0 (FALSE) if you enter a bigger number.

but if you look at the calls of average (those were made in the printf statements, which do output to console window), you will see that there were exactly 3 calls for average, each using the right argument types. that is what you required and not bad, but actually it is not very surprising that when calling average with two arguments of type float that it will use the right function. that is not so much different as if you used a name 'average_of_floats' as function name. it shows that overloading isn't something that helps from deducing an input type.

that means your design of the program to test overloading is not so good and computing the avarage is not so good for overloading either.

i would suggest you to test overloading on a to_string conversion function, so that the prototypes would be

string to_string(int i);
string to_string(double d);
string to_string(bool b);
string to_string(char c);
string to_string(unsigned char uc);

for that you would include

#include <string>
#include <iostream>
using namespace std;  // to avoid std:: prefix

then ask the user what they want to input (1 for int, 2 for double, ...) and then use the appropriate cin statement:

if (choice == 1)
{
      int i;
      cin >> i;
      cout << to_string(i) << endl;  // here the right overload was called
}
else if (choice == 2)
{
     double d;
     ...

Open in new window



if you want to go that way, you may ask whenever you need more help.

Sara

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial