C++学习笔记——(四)重载、函数模板

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

原文地址:https://www.cnblogs.com/snailt/p/13600494.html