Function overloading. Inline (inline) functions

The C++ language has implemented the ability to use one identifier for functions that perform different actions on various types data, as a result of which you can use several functions with the same name, but with different lists parameters, both in quantity and type.

Such functions are called overloaded, and the mechanism itself – overloadfunctions.

The compiler determines which function with the same name should be called by comparing the types of the actual arguments with the types of the formal parameters in the headers of all these functions, i.e.

The compiler, depending on the type and number of arguments, will form the necessary call to the corresponding function.

Finding the function to call takes three separate steps:

1. Search for a function with an exact match of parameters and use it if found.

2. Find the corresponding function using built-in data type conversions.

3. Find the corresponding function using user-defined transformations.

Function Overloading Example Let's give an example of a function S 1 with two parameters,X at

, which works depending on the type of arguments passed, as follows: Let's give an example of a function– if the parameter type is integer, the function

1 adds their values ​​and returns the resulting sum; – if the type of parameters long Let's give an example of a function, function

1 multiplies their values ​​and returns the resulting product; Let's give an example of a function– if the type of parameters is real, the function

1 divides their values ​​and returns the quotient of the division.

#include

int S1 (int x, int y) (

long S1 (long x, long y) (

double S1 (double x, double y) (

int a = 1, b = 2, c;

long i = 3, j = 4, k;

double x = 10, y = 2, z;

printf("\n c = %d; k = %ld; z = %lf . \n", c, k, z);

As a result we get: = 3; c = 12; k = 5.000000 .

z

Functions with a variable number of parameters

An ellipsis in the list of parameters of a user-defined function is used when the number of arguments is not known in advance. In this case, an indefinite number of parameters can be specified in its prototype as follows: (void f1 , int a , …);

double b This notation indicates to the compiler that behind the required actual arguments for parameters a And b

Let us list the main features of using this mechanism.

1. Several macro commands are used to access the parameters of such functions, these are:

va _ list a va _ start – macro commands for preparing access to parameters;

va _ arg – use of parameters;

va _ end – cleaning before leaving.

They are declared in the header file stdarg . h .

2. Such a function must have at least one parameter (named) to convey to it the number of arguments to be passed.

3. For the macro va_ start you need to pass two arguments - the name of the list of parameters that specifies va_ list and their number.

4. You cannot violate the specified order of macro commands. Otherwise, you can get unpredictable consequences.

5. For the macro va_ arg In addition to the name of the list of parameters, you need to pass the expected type. If the types do not match, an error occurs.

Using ellipses completely disables parameter type checking. The ellipsis is only necessary if both the number of parameters and their type are changing.

The following example illustrates this possibility.

#include

#include

void f1(double s, int n ...) (

va_start(p, n);

printf(" \n Double S = %lf ", s);

for(int i=1; i<=n; i++) {

v = va_arg(p, int);

printf("\n Argument %d = %d ", i, v);

void main(void) (

f1(1.5, 3, 4, 5, 6);

printf("\n c = %d; k = %ld; z = %lf . \n", c, k, z);

Double Let's give an example of a function = 1.500000

Argument 1 = 4

Argument 2 = 5

Argument 3 = 6

Press any key to continue

When defining functions in your programs, you must specify the type of value the function returns, as well as the number of parameters and the type of each parameter. In the past (if you programmed in C), when you had a function called add_values ​​that worked with two integer values, and you wanted to use a similar function to add three integer values, you would create a function with a different name. For example, you could use add_two_values ​​and add_three_values. Likewise, if you wanted to use a similar function to add floats, you would need another function with another name. To avoid function duplication, C++ allows you to define multiple functions with the same name. During the compilation process, C++ takes into account the number of arguments used by each function and then calls exactly the required function. Giving the compiler a choice among several functions is called overloading. In this tutorial you will learn how to use overloaded functions. By the end of this lesson, you will have mastered the following core concepts:

Function overloading allows you to use the same name for multiple functions with different parameter types.

To overload functions, simply define two functions with the same name and return type that differ in the number of parameters or their type.

Function overloading is a feature of C++ that is not found in C. As you will see, function overloading is quite convenient and can improve the readability of your programs.

FIRST INTRODUCTION TO FUNCTION OVERLOADING

Function overloading allows your programs to define multiple functions with the same name and return type. For example, the following program overloads a function named add_values. The first function definition adds two int values. The second definition of the function adds three values. During compilation, C++ correctly determines the function to use:

#include

int add_values(int a,int b)

{
return(a + b);
)

int add_values ​​(int a, int b, int c)

(
return(a + b + c);
)

{
cout<< «200 + 801 = » << add_values(200, 801) << endl;
cout<< «100 + 201 + 700 = » << add_values(100, 201, 700) << endl;
}

As you can see, the program defines two functions called add_values. The first function adds two int values, while the second adds three values. You don't have to do anything specifically to warn the compiler about overloading, just use it. The compiler will figure out which function to use based on the parameters the program offers.

Similarly, the following program MSG_OVR.CPP overloads the show_message function. The first function, named show_message, displays a standard message; no parameters are passed to it. The second displays the message sent to it, and the third displays two messages:

#include

void show_message(void)

{
cout<< «Стандартное сообщение: » << «Учимся программировать на C++» << endl;
}

void show_message(char *message)

{
cout<< message << endl;
}

void show_message(char *first, char *second)

{
cout<< first << endl;
cout<< second << endl;
}

{
show_message();
show_message("Learning to program in C++!");
show_message("There are no prejudices in C++!","Overloading is cool!");
}

WHEN OVERLOAD IS NECESSARY

One of the most common uses of overloading is to use a function to obtain a specific result based on various parameters. For example, suppose your program has a function called day_of_week that returns the current day of the week (0 for Sunday, 1 for Monday, ..., 6 for Saturday). Your program could overload this function so that it correctly returns the day of the week if it is given a Julian day as a parameter, or if it is given a day, month, and year:

int day_of_week(int julian_day)

{
// Operators
}

int day_of_week(int month, int day, int year)

{
// Operators
}

As you learn object-oriented programming in C++, introduced in the following lessons, you will use function overloading to extend the capabilities of your programs.

Function overloading improves program readability

C++ function overloading allows your programs to define multiple functions with the same name. Overloaded functions must return values ​​of the same type*, but may differ in the number and type of parameters. Before the introduction of function overloading in C++, C programmers had to create multiple functions with almost identical names. Unfortunately, programmers wishing to use such functions had to remember which combination of parameters corresponded to which function. On the other hand, function overloading makes things easier for programmers by requiring them to remember only one function name.* Overloaded functions are not required to return values ​​of the same type because the compiler uniquely identifies a function by its name and the set of its arguments. To the compiler, functions with the same names but different argument types are different functions, so the return type is the prerogative of each function. - Translator's note

WHAT YOU NEED TO KNOW

Function overloading allows you to specify multiple definitions for the same function. During compilation, C++ will determine which function to use based on the number and type of parameters passed. In this lesson, you learned that overloading functions is quite simple. In Lesson 14, you'll learn how C++ references simplify the process of changing parameters within functions. However, before moving on to Lesson 14, make sure you have learned the following basic concepts:

  1. Function overloading provides multiple "looks" at the same function within your program.
  2. To overload functions, simply define multiple functions with the same name and return type, differing only in the number and type of parameters.
  3. During compilation, C++ will determine which function to call based on the number and type of parameters passed.
  4. Function overloading simplifies programming by allowing programmers to work with only one function name.

Annotation: The lecture discusses the concepts, declaration and use of substituted and overloaded functions in programs in C++, mechanisms for performing substitution and overloading of functions, recommendations for increasing the efficiency of programs by overloading or substituting functions.

Purpose of the lecture: study inline functions and function overloading, learn to develop programs using function overloading in C++.

Inline functions

Calling a function, passing values ​​to it, returning a value - these operations take quite a lot of CPU time. Typically, when defining a function, the compiler reserves only one block of memory locations to store its statements. After the function is called, control of the program is transferred to these statements, and upon return from the function, program execution resumes from the line following the function call.

When called repeatedly, the program will execute the same set of commands each time, without creating copies for each call separately.

Each jump to a memory area containing function statements slows down program execution. If a function takes up a small amount of space, you can gain time savings from multiple calls by instructing the compiler to embed the function code directly into the program at the point of call. Such functions are called substituted. In this case, speaking about efficiency, first of all, we mean the speed of program execution.

Substituted or built-in (inline) functions– these are functions whose code is inserted by the compiler directly at the call site, instead of transferring control to a single instance of the function.

If a function is an inline function, the compiler does not create this function in memory, but copies its lines directly into the program code at the place where it is called. This is equivalent to writing appropriate blocks in the program instead of function calls. So the specifier inline defines for the function the so-called internal binding, which consists in the fact that the compiler substitutes commands of its code instead of calling a function. Inline functions are used if the function body consists of several statements.

This approach allows you to increase the speed of program execution, since commands are excluded from the program microprocessor, required to pass arguments and call the function.

For example:

/*function returns the distance from a point with coordinates (x1,y1) to a point with coordinates (x2,y2)*/ inline float Line(float x1,float y1,float x2, float y2) ( return sqrt(pow(x1-x2 ,2)+pow(y1-y2,2));

However, it should be noted that using inline functions does not always lead to a positive effect. If such a function is called several times in the program code, then compile time The same number of copies of this function will be inserted into the program as there are calls to it. There will be a significant increase in the size of the program code, as a result of which the expected increase in the efficiency of program execution over time may not occur.

Example 1.

#include "stdafx.h" #include using namespace std; inline int Cube(int x); int _tmain(int argc, _TCHAR* argv)( int x=2; float y=3; double z=4; cout<

Let's list the reasons why a function with the inline specifier will be treated as a regular non-inline function:

  • the function being substituted is recursive;
  • functions for which a call is placed before its definition;
  • functions that are called more than once in an expression;
  • functions containing loops, switches and transition operators;
  • functions that are too large to do the substitution.

Limitations on how to perform substitution are largely implementation dependent. If for a function with a specifier inline the compiler cannot perform the substitution due to the context in which the call to it is placed, then the function is considered static and is issued warning message.

Another feature of inline functions is that they cannot be changed without recompiling all parts of the program in which these functions are called.

Function overloading

When defining functions in programs, it is necessary to indicate the type of value returned by the function, as well as the number of parameters and the type of each of them. If you wrote a function in C++ called add_values ​​that worked with two integer values, and your program needed to use a similar function to pass three integer values, then you would create a function with a different name. For example, add_two_values ​​and add_three_values. Likewise, if you need to use a similar function to work with float values, then you need another function with another name. To avoid function duplication, C++ allows you to define multiple functions with the same name. During the compilation process, C++ takes into account the number of arguments used by each function and then calls exactly the required function. Giving the compiler a choice among several functions is called overloading.

Function Overloading is the creation of several functions with the same name, but with different parameters. By different parameters we mean what should be different number of arguments functions and/or their type. That is, function overloading allows you to define multiple functions with the same name and return type.

Function overloading is also called polymorphism of functions. “Poly” means many, “morphe” means form, that is, a polymorphic function is a function characterized by a variety of forms.

Function polymorphism refers to the existence in a program of several overloaded versions of a function that have different meanings. By changing the number or type of parameters, you can give two or more functions the same name. In this case, there will be no confusion, since the required function is determined by the coincidence of the parameters used. This allows you to create a function that can operate on integer, real, or other value types without having to create separate names for each function.

Thus, thanks to the use overloaded functions, you don't have to worry about calling the right function in your program that matches the type of variables being passed. When you call an overloaded function, the compiler will automatically determine which variant of the function to use.

For example, the following program overloads a function named add_values. The first function definition adds two int values. The second function definition adds three int values. During compilation, C++ correctly determines the function to use:

#include "stdafx.h" #include using namespace std; int add_values(int a,int b); int add_values(int a, int b, int c); int _tmain(int argc, _TCHAR* argv)( cout<< "200+801=" << add_values(200,801) << "\n"; cout << "100+201+700=" << add_values(100,201,700) << "\n"; system("pause"); return 0; } int add_values(int a,int b) { return(a + b); } int add_values (int a, int b, int c) { return(a + b + c); }

So the program defines two functions called add_values. The first function adds two values, while the second adds three values ​​of the same int type. The C++ compiler determines which function to use based on the parameters offered by the program.

Using Function Overloading

One of the most common uses of overloading is to use a function to obtain a specific result based on various parameters. For example, suppose your program has a function called day_of_week that returns the current day of the week (0 for Sunday, 1 for Monday, ..., 6 for Saturday). The program could overload this function so that it correctly returns the day of the week if it is given a Julian day as a parameter, or if it is given a day, month, and year.

int day_of_week(int julian_day) ( // operators) int day_of_week(int month, int day, int year) ( // operators)

Using overloaded functions A number of mistakes are often made. For example, if functions differ only in their return type but not in their argument types, those functions cannot have the same name. The following overload option is also unacceptable:

int function_name(int argument_name); int function_name(int argument_name); /*invalid name overloading: arguments have the same number and same type*/

Benefits of function overloading:

  • Function overloading improves readability programs;
  • C++ function overloading allows programs to define multiple functions with the same name;
  • overloaded functions return values ​​of the same type, but may differ in the number and type of parameters;
  • Function overloading makes things easier for programmers by requiring them to remember only one function name, but then they must know which combination of parameters corresponds to which function.

Example 2.

/*Overloaded functions have the same names, but different parameter lists and return values*/ #include "stdafx.h" #include using namespace std; int average(int first_number, int second_number, int third_number); int average(int first_number, int second_number); int _tmain(int argc, _TCHAR* argv)(// main function int number_A = 5, number_B = 3, number_C = 10; cout<< "Целочисленное среднее чисел " << number_A << " и "; cout << number_B << " равно "; cout << average(number_A, number_B) << ".\n\n"; cout << "Целочисленное среднее чисел " << number_A << ", "; cout << number_B << " и " << number_C << " равно "; cout << average(number_A, number_B, number_C) << ".\n"; system("PAUSE"); return 0; }// конец главной функции /*функция для вычисления целочисленного среднего значения 3-х целых чисел*/ int average(int first_number, int second_number, int third_number) { return((first_number + second_number + third_number)/3); } // конец функции /*функция для вычисления целочисленного среднего значения 2-х целых чисел*/ int average(int first_number, int second_number) { return((first_number + second_number)/2); } // конец функции

Function overloading means defining several functions (two or more) with the same name but different parameters. Sets of parameters of overloaded functions may differ in order, number, and type. Thus, function overloading is necessary in order to avoid duplication of function names that perform similar actions, but with different program logic. For example, consider the areaRectangle() function, which calculates the area of ​​a rectangle.

Float areaRectangle(float, float) //function that calculates the area of ​​a rectangle with two parameters a(cm) and b(cm) ( return a * b; // multiply the lengths of the sides of the rectangle and return the resulting product)

So, this is a function with two parameters of the float type, and the arguments passed to the function must be in centimeters, the return value of the float type must also be in centimeters.

Let's assume that our initial data (the sides of the rectangle) are given in meters and centimeters, for example: a = 2m 35 cm; b = 1m 86 cm. In this case, it would be convenient to use a function with four parameters. That is, each length of the sides of the rectangle is passed to the function according to two parameters: meters and centimeters.

Float areaRectangle(float a_m, float a_sm, float b_m, float b_sm) // function that calculates the area of ​​a rectangle with 4 parameters a(m) a(cm); b(m) b(cm) ( return (a_m * 100 + a_sm) * (b_m * 100 + b_sm); )

In the body of the function, the values ​​that were transmitted in meters (a_m and b_m) are converted into centimeters and summed with the values ​​a_sm b_sm, after which we multiply the sums and get the area of ​​the rectangle in cm. Of course, it was possible to convert the original data into centimeters and use the first function, but not about that now.

Now, the most important thing is that we have two functions, with different signatures, but the same names (overloaded functions). A signature is a combination of a function name and its parameters. How to call these functions? And calling overloaded functions is no different from calling regular functions, for example:

AreaRectangle(32, 43); // a function will be called that calculates the area of ​​the rectangle with two parameters a(cm) and b(cm) areaRectangle(4, 43, 2, 12); // a function will be called that calculates the area of ​​the rectangle with 4 parameters a(m) a(cm); b(m) b(cm)

As you can see, the compiler will independently select the desired function, analyzing only the signatures of overloaded functions. Bypassing function overloading, one could simply declare a function with a different name, and it would do its job well. But imagine what will happen if you need more than two such functions, for example 10. And for each you need to come up with a meaningful name, and the hardest thing is to remember them. This is precisely why it is easier and better to overload functions, unless of course there is a need for it. The source code of the program is shown below.

#include "stdafx.h" #include << "S1 = " << areaRectangle(32,43) << endl; // вызов перегруженной функции 1 cout << "S2 = " << areaRectangle(4, 43, 2, 12) << endl; // вызов перегруженной функции 2 return 0; } // перегруженная функция 1 float areaRectangle(float a, float b) //функция, вычисляющая площадь прямоугольника с двумя параметрами a(см) и b(см) { return a * b; // умножаем длинны сторон прямоугольника и возвращаем полученное произведение } // перегруженная функция 2 float areaRectangle(float a_m, float a_sm, float b_m, float b_sm) // функция, вычисляющая площадь прямоугольника с 4-мя параметрами a(м) a(см); b(м) b(cм) { return (a_m * 100 + a_sm) * (b_m * 100 + b_sm); }

// code Code::Blocks

// Dev-C++ code

#include using namespace std; // prototypes of overloaded functions float areaRectangle(float a, float b); float areaRectangle(float a_m, float a_sm, float b_m, float b_sm); int main() ( cout<< "S1 = " << areaRectangle(32,43) << endl; // вызов перегруженной функции 1 cout << "S2 = " << areaRectangle(4, 43, 2, 12) << endl; // вызов перегруженной функции 2 return 0; } // перегруженная функция 1 float areaRectangle(float a, float b) //функция, вычисляющая площадь прямоугольника с двумя параметрами a(см) и b(см) { return a * b; // умножаем длинны сторон прямоугольника и возвращаем полученное произведение } // перегруженная функция 2 float areaRectangle(float a_m, float a_sm, float b_m, float b_sm) // функция, вычисляющая площадь прямоугольника с 4-мя параметрами a(м) a(см); b(м) b(cм) { return (a_m * 100 + a_sm) * (b_m * 100 + b_sm); }

The result of the program is shown in Figure 1.