ITEEDU

3.19 一元作用域运算符

可以声明同名的局部变量和全局变量。C++提供一元作用域运算符(::),可以在同名局部变量的作用域中访问全局变量。一元作用域运算符不能在外层块中访问同名的局部变量。如果在作用域内没有与全局变量同名的局部变量,则可以直接访问全局变量,而不用一元作用域运算符。第6章将介绍类中使用的二元作用域运算符。

图3.24演示了当局部变量与全局变量同名时一元作用域运算符的用法。为了突出常量变量PI的局部和全局版本之间的差别,程序将其中一个声明为double.一个声明为float。

常见编程错误3.32

想用一元作用城运算符在外层块中访问非全局变量时,如果外层块中没有同名全局变量,则出现语法错误,如果有同名全局变量,则出见逻辑错误。

// Fig. 3.24: figO3_24.cpp
 // Using the unary scope resolution operator

 #include <iostream.h>
#include <iomanip.h> const double PI = 3.14159265358979; int main( ) { const float PI = static_cast< float >( ::PI ); cout << setprecision{ 20 ) <<" Local float value of PI = "<< PI << " Global double value of PI = "<< ::PI << endl; return 0; }

输出结果:

Local float value of PI = 3.14159

Global double value of PI = 3.14159265358979

图3.24使用一元作用域运算符

编程技巧3.14
程序中不同用途的变量不要用相同名称。尽管不同用途的变量也可以用相同名称,但容易速成混乱。

3.20 函数重载

C++允许定义多个同名函数,只要这些函数有不同参数集(至少有不同类型的参数)。这个功 能称为函数重载(function overloading)。调用重载函数时,C++编译器通过检查调用中的参数个数、 类型和顺序来选择相应的函数。函数重载常用于生成几个进行类似任务而处理不同数据类型的同名 函数。

编程技巧3.15

用函数重载完成类似的任务可以使程序易于阅读和理解。

图3.25用重载函数square计算int类型值的平方以及double类型值的平方。第8章将介绍如何 重载运算符,定义其如何对用户自定义数据类型的对象进行操作(事实上,我们已经使用了许多已重载的运算符,包括流插入运算符“ <<”和流读取运算符“>>”。第8章将详细介绍重载“>>”和 “<<”)。3.21节介绍的函数模板自动产生重载函数,对不同数据类型完成相同的任务。第12章将详细介绍函数模板和类模板。

 // Fig. 3.25: fig03_25.cpp
 // Using overloaded functions
 #include < iostream.h>
 iht square( iht x ) { return x * x; }
 double square( double y ) { return y * y; }
 int main( )
 {
 cout << "The square of integer 7 is" << square( 7 )
 << " The square of double 7.5 is" << square( 7.5 )
 << endl;
 return 0;
 } 

输出结果:

The square of integer 7 is 49

The square of double 7.5 is 56.25

图 3.25 使用重载函数

重载函数通过签名(signature)进行区别,签名是函数名和参数类型的组合。编译器用参数个数和类型编码每个函数标识符(有时称为名字改编或名字修饰),以保证类型安全连接(type-safelinkage)。类型安全连接保证调用合适的重载函数井保证形参与实参相符。编译器能探测和报告连接错误。图3.26的程序在Borland C++编译器上编译,我们不显示程序执行的输出,图中用汇编语言输出了由Borland C++编译器产生的改编函数名。每个改编名用@加上函数名,改编参数表以$q开头。在函数nothing2的参数表中,zc表示char、i表示int、pf表示float*、pd表示double*。在函数nothing1的参数表中,i表示int、f表示float、zc表示char、pi表示int*。两个square函数用参数表区分,一个指定d表示double,一个指定i表示沁。函数的返回类型不在改编名称中指定。函数名改编是编译器特定的。重载函数可以有不同返回类型.但必须有不同参数表。

常见编程错误3.33

用不同返回类型和相同参数表生成重载函数是个语法错误。

 // Name mangling
 lnt square( int x ) ( return x * x; }
 double square( double y ) ( return y * y; }
 void nothing1( int a, float b, char c, int *d )
 { } // empty function body
 char *nothing2( char a, int b, float *c, double *d )
 { return 0; }
 int main( )
 {
 return 0;
 } 

输出结果:

public _main

public @nothing2$qzcipfpd

public @nothing1$qifzcpi

public @square$qd

public @square$qi

图3.26 名字改编以保证类型安全连接

编译器只用参数表区别同名函数。重载函数不一定要有相同个数的参数。程序员使用带默认参数的重载函数时要小心,以免出现歧义。

常见编程错误3.34

调用省略默认参数的函数时可能与调用另一重载函数相同,这是个语法错误。例如,如果程序中的函数不带参数,有一个同名函数包含全部默认参数,则不带参数调用这个函数时就会造成语法措误。

3.21 函数模板

重载函数通常用于不同数据类型用不同程序逻辑进行类似的操作。如果每种数据类型的程序逻辑和操作相同.那么用函数模板(fuction template)完成这项工作更加简洁和方便。程序员编写一个函数模板定义。根据函数调用中提供的参数类型,C++自动产生不同模板函数(template function)

来处理不同类型的调用。这样,定义一个函数模板即可定义一系列的解决方案。

所有的函数模板定义都是以关键字template开头,之后是用尖括号( < >)括起来的形式参数表。每一个形式参数之前都有关键字class。形式参数是内部类型或用户自定义类型,指定函数的参数类型及返回类型,在函数定义体中声明变量,然后和任何其他函数中一样进行函数定义。

图3.27使用如下的函数模板定义:

template < class T >
T maximum{ T valuel, T value2, T value3 )
{
T max = valuel; 
if ( value2 > max )
max = value2; 
if ( value3 > max )
max = value3; 
return max; 
}

这个函数模板声明一个形式参数T为函数maximum要测试的数据类型。编译器发现程序源代码中的maximum调用时,传人maximum的数据类型代替整个模板定义中的T,C++生成一个完整函数,确定三个指定数据类型值的最大值,然后编译新生成的函数。可以看出,模板就是一种代码产生工具。

图3.27中实例化三个函数:一个取三个int值,一个取三个double值,一个取三个char值。int类型的实例化如下所示:

int maximum(int valuel int value2, int value3 )
{
int max - valuel; 
if ( value2 > max
max = value2; 
if ( value3 > max
max = value3; 
return max; 
}

板定义中的每种参数都要在函数的参数表中至少出现一次。类型参数名在特定模板定义的形式参数表中必须惟一。

图3.27演示用maximum确定三个int值、三个double值和三个char值的最大值。

  // Fig. 3.27: fig03_27.cpp
 // Using a function template
include < iostream.h>
 template < class T >
 T maximum( T value1, T value2, T value3 )
 {
 T max = valuel;
 if( value2 > max )
 if ( value3 > max )
 max = value3;
 return max;
 }
 int main( )
 {
 int intl, int2, int3;
 cout << "Input three integer values: ";
 cin >> i,tl >> int2 >> int3;
 cout << "The maximum i.teger value is:"
 << maximum{ intl, int2, int3 ); // int version
 double doublel, double2, double3;
 cout << " Input three double values: ";
 cin >> doublel >> double2 >> double3;
 cout << "The maximum double value is:"
 << maximum( doublel, double2, double3 ); // double version
 char charl, char2, char3;
 cout << " Input three characters: ";
 cin >> charl >> char2 >> char3;
 cout << "The maximum character value is:"
 << maximum( charl, char2, char3 ) // char version
 << endl;
 return 0;
 }

输出结果:

Input three integer values: 1 2 3

The maximum integer value is: 3

Input three double values:3.3 2.2 1.1

The maximum double value is: 3.3

Input three characters: A C B

The maximum character value is: C

图 3.27 使用函数模板

常见编程错误3.35

函数模板中的每个类型参数前都要放上class关键字,否则属于语法错误。

常见编程错误3.36
在函数签名中不使用函数模板的每个类型参数属于语法错误。