[C++] Function overloading and reference

Table of contents

1. Function overloading

 1. The concept of function overloading

 2. Name modification

2. Citation

 1. Reference concept

 2, citation characteristics

 3. Often quoted

 4. Referenced usage scenarios

   4.1 Make parameters

   4.2 Do the return value

 5. Comparison of pass-by-value and pass-by-reference efficiency

 6. The difference between references and pointers


1. Function overloading

 1. The concept of function overloading

Function overloading: It is a special case of functions. C++ allows several functions with the same name to declare similar functions in the same scope . The formal parameter lists ( number of parameters or type or type order ) of these functions with the same name are different , which are often used to deal with Implementing functions is similar to the problem of different data types.

#include<iostream>
using namespace std;

// 1、参数类型不同
int Add(int left, int right)
{
	cout << "int Add(int left, int right)" << endl;
	return left + right;
}
double Add(double left, double right)
{
	cout << "double Add(double left, double right)" << endl;
	return left + right;
}
// 2、参数个数不同
void f()
{
	cout << "f()" << endl;
}
void f(int a)
{
	cout << "f(int a)" << endl;
}
// 3、参数类型顺序不同
void f(int a, char b)
{
	cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
	cout << "f(char b, int a)" << endl;
}
int main()
{
	Add(10, 20);      //调用int Add(int left, int right)
	Add(10.1, 20.2);  //调用double Add(double left, double right)
 
	f();              //调用void f()
	f(10);            //调用void f(int a)

	f(10, 'a');       //调用void f(int a, char b)
	f('a', 10);       //调用void f(char b, int a)
	return 0;
}

 2. Name modification

  The reason why C++ supports function overloading lies in name modification, but why does C++ support function overloading, but C language does not support function overloading?

  In C/C++, for a program to run, it needs to go through the following stages: preprocessing, compiling, assembling, and linking .

  In the compilation stage , the compiler will modify the name of each function implementation, and then match the modified name when the function is called, give the address of the matched function to the function call, and use the call instruction to reach the corresponding The implementation of the function is carried out at the function implementation. The reason why C++ supports function overloading and C language does not support function overloading is that their function name decoration rules are different . In C language, the name of the function after modification remains unchanged, so for the function, it does not know which function to call, and in C++, different function names will appear due to different parameter types after function modification, so every time A function will call the appropriate function implementation according to its parameter type.

From the following, we can see that the name of the gcc function remains unchanged after modification. And the modified function of g++ becomes [_Z+function length+function name+type initials].

  • The result after compiling with a C language compiler

   Conclusion: Under linux, after compiling with gcc, the modification of the function name has not changed. 

  • The result after compiling with a C++ compiler

   Conclusion: Under Linux, after compiling with g++, the modification of the function name changes, and the compiler adds the function parameter type information to the modified name.

  •  Name modification rules under Windows

2. Citation

 1. Reference concept

A reference is not a new definition of a variable, but an alias for an existing variable . The compiler will not open up memory space for the reference variable, and it shares the same memory space with the variable it refers to . It's like giving people nicknames.

 Type & reference variable name (object name) = reference entity;

void TestRef()
{
    int a = 10;
    int& ra = a;     //<====定义引用类型
    printf("%p\n", &a);
    printf("%p\n", &ra);
}

   Their addresses are the same, indicating that they both share a memory space.

   Note: The reference typebethe same typeas the referencedentity.

 2, citation characteristics

  1. References must be initialized when they are defined;
  2. A variable can have multiple references;
  3. Once a reference refers to an entity, it cannot refer to another entity
void TestRef()
{
    int a = 10;
    // int& ra;   // 该条语句编译时会出错
    int& ra = a;
    int& rra = a;

    int b = 20;
    //int& ra = b;  // 该条语句编译时会出错

    printf("%p %p %p\n", &a, &ra, &rra);
}

  Their addresses are also the same.

 3. Often quoted

void TestConstRef()
{
    const int a = 10;
    //int& ra = a;   // 该语句编译时会出错,a为常量
    const int& ra = a;

    // int& b = 10; // 该语句编译时会出错,b为常量
    const int& b = 10;

    double d = 12.34;
    //int& rd = d; // 该语句编译时会出错,类型不同
    const int& rd = d;
}

 4. Referenced usage scenarios

   4.1 Make parameters

Making parameters is equivalent to copying the parameters, and there is no need to re-open up space for these two parameters.

#include<iostream>
using namespace std;
void swap(int& left, int& right)
{
	int tmp = left;
	left = right;
	right = tmp;
}
int main()
{
	int a = 10, b = 20;
	cout << "交换前:" << a << " " << b << endl;
	swap(a, b);
	cout << "交换后:" << a << " " << b << endl;
	return 0;
}

   4.2 Do the return value

First, let's look at a piece of code:

#include<iostream>
using namespace std;
int& fun()
{
	int a = 10;
	return a;
}
int main()
{
	int& ret = fun();
	cout << ret << endl;
	return 0;
}

operation result:

Looking at the above operation results, we get the results we want, but this situation is a coincidence, in fact, there are hidden secrets inside.

#include<iostream>
using namespace std;
int& fun()
{
	int a = 10;
	return a;
}
int main()
{
	int& ret = fun();
    //在这多加一行代码
	cout << "hello world" << endl;
	cout << ret << endl;
	return 0;
}

 operation result:

Why add one more line of code, the result is not what we want?

Because the variable a is a local variable, it will be destroyed when it goes out of the scope of the function. Before the destruction, we use a temporary reference variable to save the reference of a (assuming that the temporary variable is tmp (type is int&)), we find Both tmp and ret are aliases of the variable a, and a is released when it goes out of scope. If we did not add that code, the output result is correct, because a has not been changed after the space is released. If you want Adding a line of code is equivalent to re-establishing the stack frame. At this time, a has been modified, so the return value will be some random value.

To modify the above code is to set the variable a as a static variable and store it in the static area, so it is ok.

#include<iostream>
using namespace std;
int& fun()
{
	static int a = 10;
	return a;
}
int main()
{
	int& ret = fun();
	cout << "hello world" << endl;
	cout << ret << endl;
	return 0;
}

operation result:

Note: If the function returns out of the scope of the function, if the returned object is still there (not yet returned to the system), you can return by reference, and if it has been returned to the system, you must return by value.

 5. Comparison of pass-by-value and pass-by-reference efficiency

Values ​​are used as parameters or return value types. During parameter passing and return, the function does not directly pass actual parameters or return the variable itself directly, but passes actual parameters or returns a temporary copy of the variable , so values ​​are used as parameters Or the return value type is very inefficient, especially when the parameter or return value type is very large, the efficiency is even lower.

 In other words, passing by value will generate a temporary copy, but passing by reference is not used, so the efficiency of passing by reference will be higher.

 6. The difference between references and pointers

In the grammatical concept, a reference is an alias, which has no independent space and shares the same space with its referenced entity. In the underlying implementation, there is actually space, because references are implemented in the form of pointers .

int main()
{
	int a = 10;

	int& ra = a;
	ra = 20;

	int* pa = &a;
	*pa = 20;

	return 0;
}

Let's look at the assembly code of references and pointers:

Differences between references and pointers:

  1. Reference conceptually defines an alias of a variable, and a pointer stores a variable address;
  2. The reference must be initialized when it is defined , and the pointer is not required;
  3. After the reference refers to an entity during initialization, it can no longer refer to other entities , and the pointer can point to any entity of the same type at any time;
  4. There are no NULL references , but there are NULL pointers;
  5. The meaning is different in sizeof: the reference result is the size of the reference type , but the pointer is always the number of bytes occupied by the address space (4 bytes under the 32-bit platform);
  6. The self-referential addition means that the referenced entity increases by 1, and the pointer self-increment means that the pointer offsets the size of a type backward;
  7. There are multi-level pointers, but no multi-level references ;
  8. There are different ways to access entities, the pointer needs to be explicitly dereferenced, and the reference compiler handles it by itself ;
  9. References are relatively safer to use than pointers .

 

 


If there are deficiencies in this article, you are welcome to comment below, and I will correct it as soon as possible.

​​​​​​​

  Old irons, remember to like and pay attention!!!   

Guess you like

Origin blog.csdn.net/m0_63198468/article/details/131218115