Function overloading. Inline (inline) functions. Function Overloading When Overloading is Necessary

C++ allows you to specify more than one definition for functions name or operator in the same area called overload function And operator overloading respectively.

An overloaded declaration is a declaration declared with the same name as a previously declared declaration in the same scope, except that both declarations have different arguments and obviously a different definition (implementation).

When you call an overload function or operator, the compiler determines the most appropriate definition to use by comparing the types of the arguments you used to call the function or operator with the types of the parameters specified in the definitions. The process of selecting the most appropriate overloaded function or operator is called overload resolution .

Function Overloading in C++

You can have multiple definitions for the same function name in the same scope. The function definition must differ from each other in the types and/or number of arguments in the argument list. You cannot overload function declarations that differ only in return type.

Below is an example where the same function print() used to print different types of data -

#include using namespace std; class printData ( public: void print(int i) ( cout<< "Printing int: " << i << endl; } void print(double f) { cout << "Printing float: " << f << endl; } void print(char* c) { cout << "Printing character: " << c << endl; } }; int main(void) { printData pd; // Call print to print integer pd.print(5); // Call print to print float pd.print(500.263); // Call print to print character pd.print("Hello C++"); return 0; }

Printing int: 5 Printing float: 500.263 Printing character: Hello C++

Operator overloading in C++

You can override or overload most of the built-in operators available in C++. In this way, the programmer can also use operators with user-defined types.

Overloaded operators are functions with special names: the keyword "operator" followed by the symbol for the operator being defined. Like any other function, an overloaded operator has a return type and a list of parameters.

Box operator+(const Box&);

declares an append operator that can be used to additions two Box objects and returns the final Box object. Most overloaded operators can be defined as regular non-member functions or as class member functions. In case we define the function above as a non-class member function, we would have to pass two arguments for each operand as follows:

Box operator+(const Box&, const Box&);

Below is an example showing the concept of operator when loading using a member function. Here an object is passed as an argument whose properties will be accessed using this object, the object that will call this operator can be accessed using this operator as described below -

#include using namespace std; class Box ( public: double getVolume(void) ( return length * breadth * height; ) void setLength(double len) ( length = len; ) void setBreadth(double bre) ( breadth = bre; ) void setHeight(double hei) ( height = hei; ) // Overload + operator to add two Box objects. Box operator+(const Box& b) ( Box box; box.length = this->length + b.length; box.breadth = this->breadth + b .breadth; box.height = this->height + b.height; private: double length; // Breadth of a box double height; ; // Main function for the program int main() ( Box Box1; // Declare Box1 of type Box Box Box2; // Declare Box2 of type Box Box Box3; // Declare Box3 of type Box double volume = 0.0; // Store the volume of a box here // box 1 specification Box1.setLength(6.0); Box1.setBreadth(7.0); // box 2 specification Box2.setLength(12.0); ; Box2.setHeight(10.0); // volume of box 1 volume = Box1.getVolume();<< "Volume of Box1: " << volume <

When the above code is compiled and executed, it produces the following output:

Volume of Box1: 210 Volume of Box2: 1560 Volume of Box3: 5400

Overloadable / Non-overloadableOperators

Below is a list of operators that can be overloaded.



How to achieve function overloading in C?

(10)

Is there a way to achieve function overloading in C? I'm looking at simple functions that can be overloaded like

Foo (int a) foo (char b) foo (float c , int d)

I think there is no direct path; I'm looking for workarounds if they exist.

I hope the below code will help you understand function overloading #include int fun(int a, ...); int main(int argc, char *argv)( fun(1,10); fun(2,"cquestionbank"); return 0; ) int fun(int a, ...)( va_list vl; va_start(vl,a ); if(a==1) printf("%d",va_arg(vl,int)); else printf("\n%s",va_arg(vl,char *));

What do you mean - no, you can't.

You can declare the va_arg function as

void my_func(char* format, ...);

But you will need to pass some information about the number of variables and their types in the first argument - for example, printf() .

Yes, sort of.

Here you give an example:

Void printA(int a)( printf("Hello world from printA: %d\n",a); ) void printB(const char *buff)( printf("Hello world from printB: %s\n",buff) ; ) #define Max_ITEMS() 6, 5, 4, 3, 2, 1, 0 #define __VA_ARG_N(_1, _2, _3, _4, _5, _6, N, ...) N #define _Num_ARGS_(... ) __VA_ARG_N(__VA_ARGS__) #define NUM_ARGS(...) (_Num_ARGS_(_0, ## __VA_ARGS__, Max_ITEMS()) - 1) #define CHECK_ARGS_MAX_LIMIT(t) if(NUM_ARGS(args)>t) #define CHECK_ARGS_MIN_LIMIT(t) if(NUM_ARGS(args) #define print(x , args ...) \ CHECK_ARGS_MIN_LIMIT(1) printf("error");fflush(stdout); \ CHECK_ARGS_MAX_LIMIT(4) printf("error");fflush(stdout) ; \ (( \ if (__builtin_types_compatible_p (typeof (x), int)) \ printA(x, ##args); \ else \ printB (x,##args); \ )) int main(int argc, char* * argv) ( int a=0; print(a); print("hello"); return (EXIT_SUCCESS); )

It will output 0 and hello.. from printA and printB.

If your compiler is gcc and you don't mind doing manual updates every time you add a new overload, you can do a macro and get the result you want from a callers perspective, not as nice to write... but it's possible

look at __builtin_types_compatible_p then use it to define a macro that does something like

#define foo(a) \ ((__builtin_types_compatible_p(int, a)?foo(a):(__builtin_types_compatible_p(float, a)?foo(a):)

but yeah, it's disgusting, it's just not

EDIT: C1X will get support for type expressions, which they look like:

#define cbrt(X) _Generic((X), long double: cbrtl, \ default: cbrt, \ float: cbrtf)(X)

As has already been said, overloading in the sense you mean is not supported by C. A common idiom to solve the problem is to have the function take a labeled conjunction. This is implemented using the struct parameter, where the struct itself consists of some type of type indicator, such as an enum , and a union of different value types. Example:

I hope the below code will help you understand function overloading typedef enum ( T_INT, T_FLOAT, T_CHAR, ) my_type; typedef struct ( my_type type; union ( int a; float b; char c; ) my_union; ) my_struct; void set_overload (my_struct *whatever) ( switch (whatever->type) ( case T_INT: whatever->my_union.a = 1; break; case T_FLOAT: whatever->my_union.b = 2.0; break; case T_CHAR: whatever-> my_union.c = "3"; ) ) void printf_overload (my_struct *whatever) ( switch (whatever->type) ( case T_INT: printf("%d\n", whatever->my_union.a); break; case T_FLOAT : printf("%f\n", whatever->my_union.b); break; case T_CHAR: printf("%c\n", whatever->my_union.c ) ) int main (int argc, char* argv) ( my_struct s; s.type=T_INT; set_overload(&s); printf_overload(&s); s.type=T_FLOAT; set_overload(&s); printf_overload(&s); s.type=T_CHAR; set_overload(&s) ; printf_overload(&s)

Can't you just use C++ and not use all the other features of C++ except that?

If there hasn't been strict C yet, I'd recommend variadic functions instead.

The following approach is similar to a2800276, but with some C99 macro macros:

// we need `size_t` #include // argument types to accept enum sum_arg_types ( SUM_LONG, SUM_ULONG, SUM_DOUBLE ); // a structure to hold an argument struct sum_arg ( enum sum_arg_types type; union ( long as_long; unsigned long as_ulong; double as_double; ) value; ); // determine an array"s size #define count(ARRAY) ((sizeof (ARRAY))/(sizeof *(ARRAY))) // this is how our function will be called #define sum(...) _sum( count(sum_args(__VA_ARGS__)), sum_args(__VA_ARGS__)) // create an array of `struct sum_arg` #define sum_args(...) ((struct sum_arg )( __VA_ARGS__ )) // create initializers for the arguments #define sum_long (VALUE) ( SUM_LONG, ( .as_long = (VALUE) ) ) #define sum_ulong(VALUE) ( SUM_ULONG, ( .as_ulong = (VALUE) ) ) #define sum_double(VALUE) ( SUM_DOUBLE, ( .as_double = (VALUE) ) ) // our polymorphic function long double _sum(size_t count, struct sum_arg * args) ( long double value = 0; for(size_t i = 0; i< count; ++i) { switch(args[i].type) { case SUM_LONG: value += args[i].value.as_long; break; case SUM_ULONG: value += args[i].value.as_ulong; break; case SUM_DOUBLE: value += args[i].value.as_double; break; } } return value; } // let"s see if it works #include int main() ( unsigned long foo = -1; long double value = sum(sum_long(42), sum_ulong(foo), sum_double(1e10)); printf("%Le\n", value); return 0; )

For the time being, _Generic _Generic this question, standard C (no extensions) is effective received support for function (rather than operator) overloading thanks to the addition of the _Generic word in C11. (supported in GCC since version 4.9)

(Overloading isn't truly "built-in" in the way shown in the question, but it's easy to destroy something that works that way.)

Generic is a compile-time operator in the same family as sizeof and _Alignof. It is described in standard section 6.5.1.1. It takes two main parameters: an expression (which will not be evaluated at runtime) and a list of type/expression associations, which is a bit like a switch block. _Generic gets the general expression type and then "switches" to it to select the final result expression from the list for its type:

Generic(1, float: 2.0, char *: "2", int: 2, default: get_two_object());

The above expression evaluates to a 2-control expression type - int , so it selects the expression associated with the int as the value. None of this is retained during execution. (The default clause is required: if you don't specify it and the type doesn't match, it will cause a compilation error.)

A way that is useful for function overloading is that it can be inserted by the C preprocessor and select a result expression based on the type of arguments passed to the control macro. So (example from the C standard):

#define cbrt(X) _Generic((X), \ long double: cbrtl, \ default: cbrt, \ float: cbrtf \)(X)

This macro implements the overloaded cbrt operation by passing the argument type to the macro, selecting the appropriate implementation function, and then passing the original macro to that function.

So, to implement your original example, we could do this:

Foo_int (int a) foo_char (char b) foo_float_int (float c , int d) #define foo(_1, ...) _Generic((_1), \ int: foo_int, \ char: foo_char, \ float: _Generic(( FIRST(__VA_ARGS__,)), \ int: foo_float_int))(_1, __VA_ARGS__) #define FIRST(A, ...) A

In this case, we could use the default: association for the third case, but this does not demonstrate how to extend the principle to multiple arguments. The end result is that you can use foo(...) in your code without worrying (much) about the type of your arguments.

For more complex situations, such as functions that overload more arguments or changing numbers, you can use utility macros to automatically create static dispatch structures:

Void print_ii(int a, int b) ( printf("int, int\n"); ) void print_di(double a, int b) ( printf("double, int\n"); ) void print_iii(int a, int b, int c) ( printf("int, int, int\n"); ) void print_default(void) ( printf("unknown arguments\n"); ) #define print(...) OVERLOAD(print, (__VA_ARGS__), \ (print_ii, (int, int)), \ (print_di, (double, int)), \ (print_iii, (int, int, int)) \) #define OVERLOAD_ARG_TYPES (int, double) #define OVERLOAD_FUNCTIONS (print) #include "activate-overloads.h" int main(void) ( print(44, 47); // prints "int, int" print(4.4, 47); // prints "double, int" print (1, 2, 3); // prints "int, int, int" print(""); // prints "unknown arguments" )

(implementation here). With some effort you can reduce the number of templates to look fairly similar to a language with built-in overloading support.

To the side it was already possible to overload quantity arguments (not type) in C99.

Please note that the way C is graded may affect you. This will pick foo_int if you try to pass it a literal character, for example, and you need some foo_int if you want your overloads to support string literals. However, overall it's pretty cool.

Leushenko's answer is really cool: only the foo example doesn't compile with GCC, which fails with foo(7) , hitting the FIRST macro and the actual function call ((_1, __VA_ARGS__) , leaving with an extra comma. Also, we're running into problems, if we want to provide additional overloads such as foo(double) .

So I decided to answer this question in more detail, including allowing empty overload (foo(void) - which caused some trouble...).

The idea now is this: define more than one generic in different macros and let the correct one be selected according to the number of arguments!

The number of arguments is quite simple, based on this answer:

#define foo(...) SELECT(__VA_ARGS__)(__VA_ARGS__) #define SELECT(...) CONCAT(SELECT_, NARG(__VA_ARGS__))(__VA_ARGS__) #define CONCAT(X, Y) CONCAT_(X, Y) # define CONCAT_(X, Y) X ## Y

That's fine, we're deciding on either SELECT_1 or SELECT_2 (or more arguments if you want/need them), so we just need the appropriate definitions:

#define SELECT_0() foo_void #define SELECT_1(_1) _Generic ((_1), \ int: foo_int, \ char: foo_char, \ double: foo_double \) #define SELECT_2(_1, _2) _Generic((_1), \ double : _Generic((_2), \ int: foo_double_int \) \)

First, an empty macro call (foo()) still creates a token, but an empty one. So the counting macro actually returns 1 instead of 0 even when the macro is called empty. We can "easily" fix this problem if we put a comma after __VA_ARGS__ conditionally, depending on whether the list is empty or not:

#define NARG(...) ARG4_(__VA_ARGS__ COMMA(__VA_ARGS__) 4, 3, 2, 1, 0)

This looked easy, but the COMMA macro is quite heavy; Luckily this topic is already covered on Jens Gustedt's blog (thanks Jens). The main trick is that function macros don't expand unless parentheses are followed, for further explanation see Jens' blog... We just need to modify the macros a bit for our needs (I'll use shorter names and fewer arguments for brevity).

#define ARGN(...) ARGN_(__VA_ARGS__) #define ARGN_(_0, _1, _2, _3, N, ...) N #define HAS_COMMA(...) ARGN(__VA_ARGS__, 1, 1, 1, 0 ) #define SET_COMMA(...) , #define COMMA(...) SELECT_COMMA \ (\ HAS_COMMA(__VA_ARGS__), \ HAS_COMMA(__VA_ARGS__ ()), \ HAS_COMMA(SET_COMMA __VA_ARGS__), \ HAS_COMMA(SET_COMMA __VA_ARGS__ ()) \) #define SELECT_COMMA(_0, _1, _2, _3) SELECT_COMMA_(_0, _1, _2, _3) #define SELECT_COMMA_(_0, _1, _2, _3) COMMA_ ## _0 ## _1 ## _2 ## _3 # define COMMA_0000 , #define COMMA_0001 #define COMMA_0010 , // ... (all others with comma) #define COMMA_1111 ,

And now we're fine...

Complete code in one block:

/* * demo.c * * Created on: 2017-09-14 * Author: sboehler */ #include void foo_void(void) ( puts("void"); ) void foo_int(int c) ( printf("int: %d\n", c); ) void foo_char(char c) ( printf("char: %c \n", c); ) void foo_double(double c) ( printf("double: %.2f\n", c); ) void foo_double_int(double c, int d) ( printf("double: %.2f, int: %d\n", c, d); ) #define foo(...) SELECT(__VA_ARGS__)(__VA_ARGS__) #define SELECT(...) CONCAT(SELECT_, NARG(__VA_ARGS__))(__VA_ARGS__) # define CONCAT(X, Y) CONCAT_(X, Y) #define CONCAT_(X, Y) X ## Y #define SELECT_0() foo_void #define SELECT_1(_1) _Generic ((_1), \ int: foo_int, \ char : foo_char, \ double: foo_double \) #define SELECT_2(_1, _2) _Generic((_1), \ double: _Generic((_2), \ int: foo_double_int \) \) #define ARGN(...) ARGN_( __VA_ARGS__) #define ARGN_(_0, _1, _2, N, ...) N #define NARG(...) ARGN(__VA_ARGS__ COMMA(__VA_ARGS__) 3, 2, 1, 0) #define HAS_COMMA(...) ARGN(__VA_ARGS__, 1, 1, 0) #define SET_COMMA(...) , #define COMMA(...) SELECT_COMMA \ (\ HAS_COMMA(__VA_ARGS__), \ HAS_COMMA(__VA_ARGS__ ()), \ HAS_COMMA(SET_COMMA __VA_ARGS__) , \ HAS_COMMA(SET_COMMA __VA_ARGS__ ()) \) #define SELECT_COMMA(_0, _1, _2, _3) SELECT_COMMA_(_0, _1, _2, _3) #define SELECT_COMMA_(_0, _1, _2, _3) COMMA_ ## _0 # # _1 ## _2 ## _3 #define COMMA_0000 , #define COMMA_0001 #define COMMA_0010 , #define COMMA_0011 , #define COMMA_0100 , #define COMMA_0101 , #define COMMA_0110 , #define COMMA_0111 , #define COMMA_ 1000 , #define COMMA_1001 , #define COMMA_1010 , #define COMMA_1011 , #define COMMA_1100 , #define COMMA_1101 , #define COMMA_1110 , #define COMMA_1111 , int main(int argc, char** argv) ( foo();

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.