3.6 函数原型
C++的最重要特性之一是函数原型(function prototype)函数原型告诉编译器函数名称、函数返回的数据类型、函数要接收的参数个数、参数类型和参数顺序,编译器用函数原型验证函数调用。
旧版C语言不进行这种检查,因此函数调用出错时,编译器可能无法发现错误。这种调用可能造成致命执行时错误或非致命执行时错误,导致很难确认的逻辑错误,函数原型能纠正这个缺陷。
软件工程视点3.8
C++中要求函数原型。用#include预处理指令从相应库的头文件中取得标准库函数的函数原型。也可以用#include取得包含读者和小组成员使用的函数原型的头文件。
软件工程视点3.9
如果函数定义出现在程序中首次使用函数之前,则不需要函数原型,这时函数定义就作为函数原型。
图3.4中maximum函数原型为:
int maximum(int,int,int);
这个原型表示maximum取三个int类型参数,返回int类型结果。注意这个函数原型与maximum函数定义的首部相同,只是不包括参数名(x、y、z)。
编程技巧3.6
许多程序置用函数原型中的参数名来说明函数,编译器将忽略这些名称。
常见编程错误3.11
忘记函数原型末尾的分号是个语法错误。
函数原型中包括函数名和参数类型的部分称为函数签名(function signature)或签名(signature)。函数签名不包括函数返回类型。
常见编程错误3.12
函数调用不符合函数原型是个语法错误。
常见编程错误3.13
函数定义不符合函数原型是个语法错误。
作为上述“常见编程错误”的例子.图3.4中如果函数原型写成:
void maximum( int,int,int );
则编译器报告错误,因为函数原型中的void返回类型与函数首部中的int返回类型不同。
函数原型的另一个重要特性是强制参数类型转换(coercion of argument),即强制参数为相应类型。例如,数学库函数sqrt可以用整数参数调用,虽然math.h中的函数原型指定double参数,但函数仍然可以顺利工作。下列语句:
cout<<sqrt(4));
能正确地求值sqrt(4),并打印结果2。函数原型使编译器将整数参数值4变为double值4.0,然后再传人sqrt中。一般来说.与函数原型中参数类型不完全相符的参数值转换为正确类型之后再进行函数调用。这种转换可能在不遵照C++提升规则(promotion rule)时造成不正确的结果。提升规则指定一种类型转换为另一种类型时怎样才能不丢失数据。在上述sqrt的例子中,int自动转换为double而不改变数值,但如果将double转换为int,则会截去double的小数部分。将大整数的类型变为小整数的类型(例如long变为short)可能造成数值改变。
提升规则适用于包含两种或多种数据类型的表达式,这种表达式也称为混合类型表达式(mixed-type expressionL混合类型表达式中每个值的类型提升为表达式中最高的类型(实际上是生成每个值的临时值并在表达式中使用,原值保持不变)。提升的另一个常见用法是在函数参数类型不符合函数定义中指定的参数类型时。图3.5显示了内部数据类型由高到低的顺序。
数据类型 long double double float unsigned long int (同unsigned long) long int (同long) unsigned int (同unsigned) int unsigned short int (同unsigned short) short int (同short) unsigned char short char
图 3.5 内部数据类型由高到低的顺序
将数值转换为较低类型可能导致数值不正确。因此,要将数值转换为较低类型,只能显式将该值赋给较低类型的变量或使用强制类型转换运算符。函数参数值变为函数原型中的参数类型.就像直接赋给这些类型的变量一样。如果square函数使用整型参数(图3.3)而用浮点参数调用,则该参数换算为int(将数值转换为较低类型),square通常返回不正确的值。例如,square(4.5) 返回 16 而不是20.25。
常见编程错误7.14
将提升规则中较高的数据类型变为较低的数据类型可能改变数据值。
常见编程错误1.15
函数未定义先调用时如果不定义函数原型属于语法错误。
软件工程视点3.10
在文件中,放在任何函数定义之外的函数原型可用于该函数原型之后所有对该函数的调用。放在函数之中的函数原型只适用于该函数中的调用。