跳到主要内容

函数的特性

默认参数

概述

在C++中引入了一个新的内容——默认参数。

默认参数指的是当函 数调用中省略了实参时自动使用的一个值。这将极大提高函数的灵活性。

设置参数的默认值

对于带参数列表的函数,必须从右向左添加默认值。

int test1(int a,int b ,int c = 1); //编译通过
int test2(int a,int b = 1,int c); //错误
int test3(int a ,int b = 1,int c = 2); //编译通过

在调用时,设置了默认值的函数的参数位置可以缺省。

函数重载

概述

默认参数让我们能够使用不同数目的参数调用同一个函数,而函数重载让我们能够使用多个同名的函数。这里这种函数重载也称之为多态。

拓展

“多态”指的是有多种形式

在编程语言和类型论中,多态(polymorphism)指为不同数据类型的实体提供统一的接口。多态类型(polymorphic type)可以将自身所支持的操作套用到其它类型的值上。

多态有以下这几种类型:

动态多态(dynamic polymorphism):通过类继承机制和虚函数机制生效于运行期。可以优雅地处理异质对象集合,只要其共同的基类定义了虚函数的接口。也被称为子类型多态(Subtype polymorphism)或包含多态(inclusion polymorphism)。在面向对象程序设计中,这被直接称为多态。 静态多态(static polymorphism):模板也允许将不同的特殊行为和单个泛化记号相关联,由于这种关联处理于编译期而非运行期,因此被称为“静态”。可以用来实现类型安全、运行高效的同质对象集合操作。C++STL不采用动态多态来实现就是个例子。 函数重载(Function Overloading) 运算符重载(Operator Overloading) 带变量的宏多态(macro polymorphism) 非参数化多态或译作特设多态(Ad-hoc polymorphism): 参数化多态(Parametric polymorphism):把类型作为参数的多态。在面向对象程序设计中,这被称作泛型编程。 对于C++语言,带变量的宏和函数重载(function overload)机制也允许将不同的特殊行为和单个泛化记号相关联。然而,习惯上并不将这种函数多态(function polymorphism)、宏多态(macro polymorphism)展现出来的行为称为多态(或静态多态),否则就连C语言也具有宏多态了。谈及多态时,默认就是指动态多态,而静态多态则是指基于模板的多态。

函数重载最主要的应用是不同的重载函数间完成相同的工作,但使用不同的参数列表。

参数列表

函数重载的关键是函数的参数列表——也称为函数特征标。如果两个函数的参数数目和类型相同,同时参数的排列顺序也相同,则它们的特征标相同,同时变量名不会影响函数特征标。C++允许定义名称相同的函数,条件是它们的特征标不同。

例如,可以定义多个相同的test函数:

int test(double a,double b);
int test(int a,int b);
int test(int a,double b);
int test(double a,float b);

使用test( … )函数时,编译器将根据所采取的用法使用有相应特征标 的原型:

WARNING: 使用被重载的函数时,需要在函数调用中使用正确的参数类型。

类型引用和类型本身视为同一个特征标

名称修饰

C++如何跟踪每一个重载函数呢?它给这些函数指定了秘密身份。使用C++开发工具中的 编辑器编写和编译程序时,C++编译器将执行一些神奇的操作——名称修饰(name decoration)或名称矫正(name mangling),它根据函数原型中指定的形参类型对每个函数名 进行加密。这种格式对于人类来说很适合;我们知道函数接受两个参数(一个为int类型,另一个为 float类型),并返回一个long值。而编译器将名称转换为不太好看的内部表示,来描述该接口。对原始名称进行的表面看来无意义的修饰(或矫正,因人而异)将对参数数目和类型进行编码。添加的一组符号随函数特征标而异,而修饰时使用的约定随编译器而异。

函数模版

现在的C++编译器实现了C++新增的一项特性——函数模版

函数 模板是通用的函数描述,也就是说,它们使用泛型来定义函数,其中的 泛型可用具体的类型(如int或double)替换。通过将类型作为参数传递 给模板,可使编译器生成该类型的函数。由于模板允许以泛型(而不是 具体类型)的方式编写程序,因此有时也被称为通用编程。由于类型是 用参数表示的,因此模板特性有时也被称为参数化类型(parameterized types)。

例如如下的方式定义:

template <typename Any>
void swap(Any &a,Any &b);

模板并不创建任何函数,而只是告诉编译器如何定义函数。需要交换int的函数时,编译器将按模板模式创建这样的函数,并用int代替Any。同样的,其他数据类型也会生效。

在标准C++98添加关键字typename之前,C++使用关键字class来创建模板

也就是说,要像如下方式来定义

template <class Any>
void swap(Any &a,Any &b);

重载函数模板

可以像重载常规函数定义那样重载模板定义。和常规重载一 样,被重载的模板的函数特征标必须不同。

template <typename a>
void swap(a a, a b , int n);