一、函数重载
1、函数重载定义
??在C++中可以为两个或两个以上的函数提供相同的函数名称,只要参数类型不同,或参数类型相同而参数的个数不同, 称为函数重载。
示例:
int my_max(int a,int b)
{
return a > b ? a : b;
}
char my_max(char a,char b)
{
return a > b ? a : b;
}
double my_max(double a,double b)
{
return a > b ? a : b;
}
int main()
{
int ix = my_max(12,23);
double dx = my_max(12.23,34.45);
char chx = my_max('a','b');
return 0;
}
2、判断函数重载的规则
- 两个函数的参数表相同, 但是返回类型不同,会被标记为编译错误:函数的重复声明。
示例:
int my_max(int a,int b)
{
return a > b ? a : b;
}
unsigned int my_max(int a,int b)
{
return a > b ? a : b;
}
int main()
{
int ix = my_max(12,23);
unsigned int = my_max(12,23);
reutrn 0;
}
示例:
int my_add(int a,int b);
int my_add(int x,int y);
- 如果在两个函数的参数表中,只有缺省实参不同,则第二个声明被视为第一个的重复声明
示例:
void Print(int *br,int n);
void Print(int *br,int len = 10);
- typedef 是数据类型的别名,如果两个函数参数表的区别旨在以一个使用了 typedef ,则该参数视为相同的参数列表。
示例:
typedef unsigned int u_int;
int Print(u_int a)
int Print(unsigned int b);
- 当一个形参类型有 const 或 volatile 修饰时,如果形参是按值传递方式定义,在识别函数声明是否相同时,并不考虑 const 和 volatile 修饰符。
示例:
void fun(int a){ }
void fun(const int a) { }
- 当一个形参类型有 const 或 volatile 修饰时,如果形参定义指针或引用时,在识别函数声明是否相同时,就要考虑 const 和 volatile 修饰符。
示例:
void fun(int *p) {}
void fun(const int *p) {}
void fun(int &a) {}
void fun(const int &a) {}
- 注意函数调用的二义性,如果在两个函数的参数表中,形参类型相同,而形参个数不同,形参默认值将会影响函数的重载。
void fun(int a){}
void fun(int a,int b){}
void fun(int a ,int b = 10);
2、名字粉碎(名字修饰)
??“C”或者“C++”函数在内部(编译和链接)通过修饰名识别。修饰名是编译器在编译函数定义或者原型时生成的字符串。 ??修饰名由函数名、类名、调用约定、返回类型、参数等共同决定。
??_stdcall 是Pascal程序的缺省调用方式,通常用于Win32 Api中,函数采用从右到左的压栈方式,自己在退出时清空堆栈。
??C调用约定(即用 _cdecl 关键字说明)按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的(正因为如此,实现可变参数的函数只能使用该调用约定)。
??thiscall 仅仅应用于“ C++ ”类的成员函数。 this 指针存放于ECX 寄存器,参数从右到左压。thiscall 不是关键词,因此不能被程序员指定。
??在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预编译(预处理)、编译、汇编、链接。Name Mangling是一种在编译过程中,将函数名、变量名的名字重新命名的机制。
(1)C语言的名字修饰规则非常简单,_cdecl是C/C++的缺省调用方式, 调用约定函数名字前面添加了下划线前缀。 格式:_functionname (2)_stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个“@”符号和其参数的字节数。 格式:_functionname@number (3)_fastcall 调用约定在输出函数名前加上一个“ @ ”符号,函数名后面也是一个“ @ ”符号和其参数的字节数 格式:@functionname@number
3、C++编译时函数名修饰约定规则:
_cdecl 调用约定: 1、以“?”标识函数名的开始,后跟函数名; 2、函数名后面以“@@YA”标识参数表的开始,后跟参数表; 3、参数表以代号表示:
- X – void ,
- D – char,
- E – unsigned char,
- F – short,
- H – int,
- I – unsigned int,
- J – long,
- K – unsigned long,
- M – float,
- N – double,
- _N – bool,
… - PA-- 表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,以“ 0 ”代替,一个“ 0 ”代表一次重复;
4、参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前; 5、参数表后以“@Z”标识整个名字的结束,如果该函数无参数,则以“ Z ”标识结束
int __stdcall my_add_int(int a, int b)
{
return a + b;
}
int main()
{
my_add_int(12, 23);
return 0;
}
4、C++函数是重载
int my_max(int a, int b);
char my_max(char a, char b);
double my_max(double a, double b);
int main()
{
my_max(12, 23);
my_max('a', 'b');
my_max(12.23, 34.45);
return 0;
}
关键字 : extern “C” : 函数名以C的方式修饰约定规则; extern “C++” : 函数名以C++的方式修饰约定规则;
二、函数模板
??为了代码重用,代码就必须是通用的;通用的代码就必须不受数据类型的限制。
??函数模板可以用来创建一个通用功能的函数,以支持多种不同形参,简化重载函数的设计。
函数模板定义如下:
template<模板参数表>
返回类型 函数名(形式参数表)
{
...;
}
??<模板参数表>(template parameter list)尖括号中不能为空,参数可以有多个,用逗号分开。模板参数主要是模板类型参数。
??模板类型参数 (template type parameter) 代表一种类型 , 由关键字 class 或 typename ( 建议用typename) 后加一个标识符构成,在这里两个关键字的意义相同,它们表示后面的参数名代表一个潜在的内置或用户设计的类型。
示例:
template<class T>
T my_max(T a, T b)
{
return a > b? a:b;
}
int main()
{
my_max(12, 23);
my_max('a', 'b');
my_max(12.23, 34.45);
return 0;
}
|