Introduction to C++: Function default parameters and function overloading

Table of contents

1. Function default parameters

1.1 Concept of default parameters

1.2 Default parameter classification

2. Function overloading

2.1 Concept of function overloading

2.2 The principle of C++ supporting function overloading


1. Function default parameters

1.1 Concept of default parameters

Default parameters specify a default value for the function's parameters when declaring or defining a function . When calling this function, if no actual parameter is specified, the default value of the formal parameter is used. Otherwise, the specified actual parameter is used, which is a bit of a backup.

void Func(int a = 0)
{
    cout << a << endl;
}
int main()
{
    Func(); // 没有传参时,使用参数的默认值 ,打印0
    Func(10); // 传参时,使用指定的实参 , 打印10
    return 0;
}

1.2 Default parameter classification

1. All default parameters

//全缺省
void Func(int a = 10, int b = 20,int c =30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl << endl;
}

int main()
{
	Func();
	
	//显示传参,必须从左往右连续显示传参,
	Func(1);
	Func(1, 2);
	Func(1, 2, 3); 
	return 0;
}

2. Semi-default parameters

半缺省,缺省部分,必须从右往左,给缺省值
void Func(int a, int b = 20, int c = 30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl << endl;
} 

int main()
{
	//没有缺省的必须传
	Func(1);
	Func(1, 2);
	Func(1, 2, 3);
}

Notice:

  1. Semi-default parameters must be given sequentially from right to left, and cannot be given at intervals.
  2. Default parameters cannot appear in function declarations and definitions at the same time . C++ stipulates that they are given in declarations but not in definitions . Error example:
    //a.h
    void Func(int a = 10);
    // a.cpp
    void Func(int a = 20)
    {}
    // 注意:如果声明与定义位置同时出现,恰巧两个位置提供的值不同,
    //那编译器就无法确定到底该用那个缺省值
  3. The default value must be a constant or global variable
  4. C language is not supported (the compiler does not support it)

Application of function default parameters:

When applying for space using a certain data structure such as a stack, if we know how much space we need to use, we can directly pass in the space size without having to realloc multiple times to adjust the space. Example:

------------------------Stack.h------------
#include<iostream.h>
#include<stdlib.h>
namespace s
{
	typedef struct Stack
	{
		int* a;
		int top;
		int capacity;
	}Stack;

	//不允许声明和定义同时给缺省参数     C++规定 声明给 定义不给
	void StackInit(Stack* ps, int n = 4);//缺省值为4

	void StackPush(Stack* ps, int x);
}
-----------------------Stack.cpp-------------
#include"Stack.h"

void s::StackInit(Stack* ps, int n)
{
	ps->a = (int*)malloc(sizeof(int) * n);
	if (ps->a == NULL)
	{
		perror("malloc fail");
		return;
	}
	ps->top = 0;
	ps->capacity = n;
}
void s::StackPush(Stack* ps, int x)
{
	if (ps->top == ps->capacity)
	{
		int* ptr = (int*)realloc(ps->a, sizeof(int) * ps->capacity * 2);
		if (ptr == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps->capacity *= 2;
	}
	ps->a[ps->top] = x;
	ps->top++;
}
----------------------test.cpp--------------
#include"Stack.h"
using namespace s;
int main()
{
	//知道要插入多少个
	Stack st1;
	StackInit(&st1, 10);
	for (int i = 0; i < 10; i++)
	{
		StackPush(&st1,i);
	}
	Stack st2;
	StackInit(&st2, 100);
	for (int i = 0; i < 100; i++)
	{
		StackPush(&st2,i);
	}
	//不知道要插入多少个时
	Stack st3;
	StackInit(&st3);

	return 0;
}

When defining a function in a header file:

Define a function in a header file. When this header file is included in multiple .cpp files, a link error will occur. If the definition is repeated, you can add static before the function to change the link attribute from external link to internal link. This can only be done in the current file usage.

2. Function overloading

In natural language, a word can have multiple meanings, and people can judge the true meaning of the word through the context, that is, the word is overloaded.

For example: There used to be a joke that you don’t need to watch or worry about the two state-owned sports. One is table tennis and the other is men's football. The former is "No one can win!" and the latter is "No one can win!"

2.1 Concept of function overloading

Function overloading: It is a special case of functions. C++ allows you to declare several functions of the same name with similar functions in the same scope . These functions with the same name have different formal parameter lists (number of parameters or types or type order). This is often used to deal with Implement functions 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 func()
{
	cout << "func()" << endl;
}

void func(int x)
{
	cout << "func = " << x << 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);
    Add(10.1, 20.2);
    //cout自动匹配类型本质也是函数重载
    f();
    f(10);
    f(10, 'a');
    f('a', 10);
    return 0;
}

Notice:

  1. The different order does not mean that the order of the names of the formal parameters is different, but that the order of the parameter types is different.
    //func1构不成函数重载,会重定义
    void func1(int x, double y)
    {
    	//...
    }
    void func1(int y, double x)
    	//...
    }
    //func2构成函数重载
    void func2(int x, double y)
    {
    	//...
    }
    void func2(double x, int y)
    {
    	//...
    }
  2. Only different return values ​​do not constitute function overloading

Different scopes cannot constitute function overloading. Expanding the namespace can also constitute it.

//不同作用域构不成函数重载,但是展开作用域后构成
namespace s1
{
	void func(int x)
	{
		cout << "func = " << x << endl;
	}
}
namespace s2
{
	void func(double x)
	{
		cout << "func = " << x << endl;
	}
}
using namespace s1;
using namespace s2;

Merging the same namespace names also constitutes function overloading

//命名空间相同合并,构成函数重载
namespace s1
{
	void func(int x)
	{
		cout << "func = " << x << endl;
	}
}
namespace s1
{
	void func(double x)
	{
		cout << "func = " << x << endl;
	}
}

Function overloading encounters function default parameters

//构成重载 参数个数不同
//调用时发生问题,调用存在歧义
void func(int x)
{
	cout << "void func(int x)" << endl;
}
void func(int x,int b = 1)
{
	cout << "void func(int x,int b = 1) " << endl;
}

int main()
{
	func(1, 2);//可以调用
	//调用时发生问题,调用存在歧义,与重载没有关系
	//func(1);
	return 0;
}

A problem occurred while calling, the call was ambiguous, but an overload occurred.

2.2 The principle of C++ supporting function overloading

Why does C++ support function overloading, but the C language does not support function overloading?

In C/C++, for a program to run, it needs to go through translation: compilation and linking . There are three stages of compilation: preprocessing, compilation, and assembly .

Program translation stage:

 Program compilation phase:

 1. Actual projects usually consist of multiple header files and multiple source files, and compilation is separated. [When the Add function defined in b.cpp is currently called in a.cpp], after compilation and before linking, there is no Add function address in the ao target file, because Add is defined in b.cpp, so the Add address in bo. So what to do?

2. So the link stage is dedicated to dealing with this kind of problem. When the linker sees that ao calls Add, but there is no Add address, it will find the Add address in bo's symbol table, and then link them together, that is, merging the symbol tables and symbols. The table has the name of each function and its corresponding address .

3. So when linking, when facing the Add function, which name will the linker use to find it? In C++, the compiler has its own function name modification rules. To distinguish overloaded functions, the modified name is placed in the symbol table . The C language directly uses the function name as the name of the symbol table without modification, so overloading will conflict .

4. Since the modification rules of vs under Windows are too complicated, while the modification rules of g++ under Linux are simple and easy to understand, below we use g++ to demonstrate the modified name.

5. From the following we can see that the name of the gcc function remains unchanged after modification. After modification, the function of g++ becomes [_Z+function length+function name+type initial letter

Example:

void func(int x, double y)
{
	cout << "void func(int x, double y)" << endl;
}
void func(double x, int y)
{
	cout << "void func(double x, int y)" << endl;
}

int main()
{
	func(1, 1.1);
	func(1.1, 1);
	return 0;
}

Calling function goes to assembly:

It can be found that the call instruction is used to jump to the address of the first line of the func function. The address of a function can essentially be considered as the address of the first instruction of the function. If it is declared but not defined, it will not be found and the address cannot be generated . The following is an error that only declares but does not define:

It can be found that the first function name has been modified as: (?func@@YAXHN@Z), int is modified as H, and double is modified as N. The order of overloaded parameters here is different, so the names of the two modified functions are also different .

Let’s take a look at the modification rules of g++ under Linux:

 One is <_Z4funcid> and the other is <_Z4funcdi>  . The function name modification rules are: [_Z + number of characters in function name + function name + first letter of type] int is i, double is d, pointer type is preceded by p, int * is pi, can be found:

The essence of the function name modification rules is to bring the parameter type into the name. Different types, different numbers, and different orders will result in different modified names. Therefore, different return values ​​cannot constitute function overloading, because there is no return value in the function name modification rules.

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

There is a question here. If the return value is brought into the function name modification rules, can it constitute overloading?

The answer is no, you will find that when calling, you don’t know who to call, example:

void func(int x, double y)
{
	//...
}
int func(int x, double y)
{
	//...
    return 1;
}
//不会构成函数重载
int main()
{
	func(1, 1.1);//不知道到底调用哪一个
    func(1, 1.1);
	return 0;
}

in conclusion: 

  1.  From here, we understand that C language cannot support overloading because functions with the same name cannot be distinguished. C++ is distinguished by function modification rules. As long as the parameters are different, the modified names are different, and overloading is supported.
  2. If the function names and parameters of two functions are the same and the return values ​​are different, it does not constitute overloading because the compiler cannot distinguish it when calling.

 This article ends.

Guess you like

Origin blog.csdn.net/qq_72916130/article/details/132379708