比拟于C语言的函数,C++增加了重载(overloaded)、内联(inline)、const和virtual四种新机制。个中重载和内联机制既可用于全局函数也可用于类的成员函数,const与virtual机制仅用于类的成员函数。 重载和内联必定有其长处才会被C++语言采用,可是不行以当成免费的午餐而滥用。本章将探究重载和内联的利益与范围性,说明什么环境下应该回收、不应回收以及要鉴戒错用。
8.1 函数重载的观念
8.1.1 重载的发源
自然语言中,一个词可以有很多差异的寄义,即该词被重载了。人们可以通过上下文来判定该词到底是哪种寄义。“词的重载”可以使语言越发简洁。譬喻“用饭”的寄义十分遍及,人们没有须要每次非得说清楚详细吃什么不行。别迂腐得象孔已己,说茴香豆的茴字有四种写法。
在C++措施中,可以将语义、成果相似的几个函数用同一个名字暗示,即函数重载。这样便于影象,提高了函数的易用性,这是C++语言回收重载机制的一个来由。譬喻示例8-1-1中的函数EatBeef,EatFish,EatChicken可以用同一个函数名Eat暗示,用差异范例的参数加以区别。
void EatBeef(…); // 可以改为 void Eat(Beef …);
void EatFish(…); // 可以改为 void Eat(Fish …);
void EatChicken(…); // 可以改为 void Eat(Chicken …);
示例8-1-1 重载函数Eat
C++语言回收重载机制的另一个来由是:类的结构函数需要重载机制。因为C++划定结构函数与类同名(请拜见第9章),结构函数只能有一个名字。假如想用几种差异的要领建设工具该怎么办?别无选择,只能用重载机制来实现。所以类可以有多个同名的结构函数。
8.1.2 重载是如何实现的?
几个同名的重载函数仍然是差异的函数,它们是如何区分的呢?我们自然想到函数接口的两个要素:参数与返回值。
假如同名函数的参数差异(包罗范例、顺序差异),那么容易区别出它们是差异的函数。
假如同名函数仅仅是返回值范例差异,有时可以区分,有时却不能。譬喻:
void Function(void);
int Function (void);
上述两个函数,第一个没有返回值,第二个的返回值是int范例。假如这样挪用函数:
int x = Function ();
则可以判定出Function是第二个函数。问题是在C++/C措施中,我们可以忽略函数的返回值。在这种环境下,编译器和措施员都不知道哪个Function函数被挪用。
所以只能靠参数而不能靠返回值范例的差异来区分重载函数。编译器按照参数为每个重载函数发生差异的内部标识符。譬喻编译器为示例8-1-1中的三个Eat函数发生象_eat_beef、_eat_fish、_eat_chicken之类的内部标识符(差异的编译器大概发生差异气势气魄的内部标识符)。
假如C++措施要挪用已经被编译后的C函数,该怎么办?
假设某个C函数的声明如下:
void foo(int x, int y);
该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会发生像_foo_int_int之类的名字用来支持函数重载和范例安详毗连。由于编译后的名字差异,C++措施不能直接挪用C函数。C++提供了一个C毗连互换指定标记extern“C”来办理这个问题。譬喻:
extern “C”
{
void foo(int x, int y);
… // 其它函数
}
可能写成
extern “C”
{
#include “myheader.h”
… // 其它C头文件
}
这就汇报C++编译译器,函数foo是个C毗连,应该到库中找名字_foo而不是找_foo_int_int。C++编译器开拓商已经对C尺度库的头文件作了extern“C”处理惩罚,所以我们可以用#include 直接引用这些头文件。
留意并不是两个函数的名字沟通就能组成重载。全局函数和类的成员函数同名不算重载,因为函数的浸染域差异。譬喻:
void Print(…); // 全局函数
class A
{…
void Print(…); // 成员函数
}
岂论两个Print函数的参数是否差异,假如类的某个成员函数要挪用全局函数Print,为了与成员函数Print区别,全局函数被挪用时应加‘::’符号。如
::Print(…); // 暗示Print是全局函数而非成员函数