C++(函数重载和函数模板)

重载和模板

  • 一、函数重载
    • 1、函数重载定义
  • 2、判断函数重载的规则
    • 2、名字粉碎(名字修饰)
    • 3、C++编译时函数名修饰约定规则:
    • 4、C++函数是重载
  • 二、函数模板

一、函数重载

1、函数重载定义

  在C++中可以为两个或两个以上的函数提供相同的函数名称,只要参数类型不同,或参数类型相同而参数的个数不同, 称为函数重载

示例:

// my_max + 参数表
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) // error;
{
	return a > b ? a : b;
}
int main()
{
	int ix = my_max(12,23);
	unsigned int = my_max(12,23); // error;
	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是一种在编译过程中,将函数名、变量名的名字重新命名的机制。

  • C 语言编译时函数名修饰约定规则

(1)C语言的名字修饰规则非常简单,_cdecl是C/C++的缺省调用方式, 调用约定函数名字前面添加了下划线前缀。
格式:_functionname
C++(函数重载和函数模板)_第1张图片
(2)_stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个“@”符号和其参数的字节数。
格式:_functionname@number
C++(函数重载和函数模板)_第2张图片
(3)_fastcall 调用约定在输出函数名前加上一个“ @ ”符号,函数名后面也是一个“ @ ”符号和其参数的字节数
格式:@functionname@number
C++(函数重载和函数模板)_第3张图片

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 ”标识结束

//(?my_add_int@@YGHHH@Z)
int __stdcall my_add_int(int a, int b)
{
	return a + b;
}
int main()
{
	my_add_int(12, 23);
	return 0;
}

4、C++函数是重载

//(?my_max@@YAHHH@Z)
int my_max(int a, int b);
//(?my_max@@YADDD@Z)
char my_max(char a, char b);
//(?my_max@@YANNN@Z)
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;
}

你可能感兴趣的:(c++)