1、函数重载
- 原理
- 允许多个函数共享同一个函数名
- 针对不同类型参数,提供不同操作
- 案例:加法操作符“+”重载
- 原因
- 对不同类型数据,执行相同的一般性操作(大量重复使用)
- 方法
- 如果两个函数的参数表中参数的个数或类型不同,则认为这两个函数是重载的
- void print( const string & );
- void print( vector<int> & );
- 如果两个函数的返回类型和参数表精确匹配,则第二个声明被视为第一个的重复声明
- void print( const string &str );
- void print( cons t string & ); // 重复声明
- 如果两个函数的参数表相同,但是返回类型不同,则第二个声明被视为第一个的错误重复声明,会被标记为编译错误
- unsigned int max( int i1, int i2 );
- int max( int , int ); // 错误: 只有返回类型不同
- 函数的返回类型不足以区分两个重载函数
- 如果在两个函数的参数表中,只有缺省实参不同,则第二个声明被视为第一个的重复声明
- int max( int *ia, int sz );
- int max( int *, int = 10 ); // 重复声明
- 如果两个函数参数表的区别,只在于一个使用了 typedef。而另一个使用了与 typedef相应的类型,则该参数表视为相同
- typedef double DOLLAR; // typedef 并不引入一个新类型
- extern DOLLAR calc( DOLLAR );
- extern int calc( double ); // 错误: 相同参数表,不同返回类型
- 当一个参数类型是 const 或 volatile 时,在识别函数声明是否相同时,并不考虑 const 和 volatile 修饰符
- void f( int );
- void f( const int ); // 重复声明
- PS:
- 参数是 const,这只跟函数的定义有关系,它意味着函数体内的表达式不能改变参数的值
- 但是,对于按值传递的参数,这对函数的用户是完全透明的
- 用户不会看到函数对按值传递的实参的改变
- 当实参被按值传递时,将参数声明为 const 不会改变可以被传递给该函数的实参种类
- 任何 int 型的实参都可以被用来调用函数 f(const int),因为两个函数接受相同的实参集
- 所以上述两个声明并没有声明一个重载函数
- 但是,如果把 const 或 volatile 应用在指针或引用参数指向的类型上,则在判断函数声明是否相同时,就要考虑 const 和 volatile 修饰符
- 如果两个函数的参数表中参数的个数或类型不同,则认为这两个函数是重载的
- 重载函数匹配
- 精确匹配
- 包括参数的强制类型转换
- 类型转换匹配(系统默认的数据类型转换)
- 不匹配
- 精确匹配
- 什么时候不使用重载
- 不同函数名可使程序更易于理解
- 参数表完全相同的两个函数
- PS:重载函数应在同一个域内声明,使用using可使不同域的函数在同一个域发生重载
2、函数模板
- 原理
- 函数模板提供了一种机制,通过它我们可以保留函数定义和函数调用的语义
- 在一个程序位置上封装了一段代码,确保在函数调用之前实参只被计算一次
- 而无需像宏方案那样绕过 C++的强类型检查
- 概述
- 函数模板提供一个种用来自动生成各种类型函数实例的算法
- 程序员对于函数接口(参数和返回类型)中的全部或者部分类型进行参数化(parameterize),而函数体保持不变
- 例子
- 用一个函数的实现在一组实例上保持不变,并且每个实例都处理一种惟一的数据类型,
- 如函数 min(),该函数就是模板的最佳候选者,下面是 min()的函数模板定义
template <class MyClass>
MyClass min( MyClas a, MyClass b ){
return a < b ? a : b;
}
int main() {
min( 10, 20 ); // ok: int min( int, int );
min( 10.0, 20.0 ); // ok: double min( double, double );
return 0;
}
- 在程序的运行过程中 MyClass 会被各种内置类型和用户定义的类型所代替
- 使用方法
- 关键字 template 总是放在模板的定义与声明的最前面
- 关键字后面是用逗号分隔的模板参数表(template parameter list), 它用尖括号括起来
- 该列表是模板参数表,不能为空
- 模板参数可以是一个模板类型参数(template type parameter),它代表了一种类型
- 模板参数也可以是一个模板非类型参数(template nontype parameter),它代表了一个常量表达式
- 特点
- 当一个名字被声明为模板参数之后它就可以被使用了,一直到模板声明或定义结束为止
- 如果在全局域中声明了与模板参数同名的对象函数或类型,则该全局名将被隐藏
- 在函数模板定义中声明的对象或类型不能与模板参数同名
- 如果一个函数模板有一个以上的模板类型参数,则每个模板类型参数前面都必须有关键字 class 或 typename
- 函数模板是对一组函数的规则描述,其本身不能定义任何函数,当对模板使用特定类型进行实例化时,才会生成一个实体函数
- 重载函数模板
- template <typename Type>
Type min( const Array<Type>&, int ); // #1
-
- template <typename Type>
Type min( const Type*, int ); // #2
-
- template <typename Type>
Type min( Type, Type ); // #3