************************************************************
原文:http://www.cplusplus.com/doc/tutorial
************************************************************
重载函数。
在
C++
中两个不同的函数如果他们的参数类型或参数个数不同的话他们可以有相同的名字。那就意味着如果他们的参数个数或参数类型不同的话,你可以把同一个名字给多个函数。例如:
<script type="text/javascript" src="http://ads.adbrite.com/mb/text_group.php?sid=170596&col=3&br=1"></script>
// overloaded function
#include <iostream>
using namespace std;
int operate (int a, int b)
{
return (a*b);
}
float operate (float a, float b)
{
return (a/b);
}
int main ()
{
int x=5,y=2;
float n=5.0,m=2.0;
cout << operate (x,y);
cout <<
"/n"
;
cout << operate (n,m);
cout <<
"/n"
;
return 0;
}
|
10
2.5
|
在这里我们定义了两个拥有相同名字的函数——
operate
——但其中一个接受两个
int
型的参数,而另一个则接受的是
float
型的。编译器通过在函数被调用时检查传入实参的类型可以辨别每次调用函数。如果调用时以两个
int
型数据作为实参则编译器会调用在原型声明中有两个
int
型形参的那个函数;当然,如果传递是两个
float
型的实参就将调用在其原型中有两个
float
型形参的那个函数。
在第一个对
operate
的调用时传递的两个实参的类型是
int
的,因此第一个原型的函数被调用了;这个函数返回两个形参的乘积。而第二个调用则传递两个
float
型的实参,因此第二个原型的函数被调用了。这个函数有不同的行为:它计算的是两个形参的商。因此被调用的
operate
的行为是由传递来的实参的类型决定的——因为函数被“重载”了。
请注意:一个函数不能仅依靠它的返回值类型来重载。至少它的一个形参必须有不同的类型。
内联函数
.
inline
说明符是一个用于优化的说明符。它不改变一个函数的行为,只是用来告诉编译器把该函数的函数体插入到在其每一个被调用处,而不是做一个传统的调用——包括把变量压栈、跳转到其他的内存区。这和声明一个“宏”是等同的。它只在非常短的函数上表现出一些优势,对于那些非常短的函数,当调用一个函数的高需求不能满足时从编译程序得到的代码可能更快。
(It only represents an overhead advantage for very short functions, in which the resulting code from compiling the program may be faster when the overhead required to call a function is avoided. )
其声明格式为:
inline type name ( arguments ... ) { instructions ... }
其调用形式和调用任何其它函数相同。当调用一个函数时,你不必一定要带有
inline
关键字,
inline
关键字只在声明一个内联函数时是必须的。
大部分的编译器已经在更合适的时候把代码优化为了内联函数。这个说明符仅是指使编译器这个函数更希望被编译为内联函数。
递归
.
递归是指函数必须要调用它们本身的性质。它对很多任务都是很有用的,像排序和计算阶乘。例如,为了得到一个数的阶乘(
n!
)数学公式是:
n! = n * (n-1) * (n-2) * (n-3) ... * 1
更具体的
, 5!
(
5
的阶乘)因该是:
5! = 5 * 4 * 3 * 2 * 1 = 120
C++
中一个计算这个的递归函数可以是:
// factorial calculator
#include <iostream>
using namespace std;
long factorial (long a)
{
if (a > 1)
return (a * factorial (a-1));
else
return (1);
}
int main ()
{
long number;
cout <<
"Please type a number: "
;
cin >> number;
cout << number <<
"! = "
<< factorial (number);
return 0;
}
|
Please type a number: 9
9! = 362880
|
注意在函数
factorial
中我们是如何包含一个对其本身的调用的,但是仅在传来的实参大于
1
时才调用其本身,因为不这样的话这个函数将是一个无尽的递归循环:一旦它达到
0
,它将继续乘所有的负数(或许会在运行时
(runtime)
引起一个栈溢出错误)。
这个函数有一个局限因为我们为了简单在它设计中所使用的数据类型
(long)
。对于远大于
10!
或
15!
的值,它给出的结果是无效的,这取决于你在什么系统上编译它。
声明函数
.
直到现在,在源代码中我们在所有函数第一次被调用之前我们都已定义了它们。这些调用一般都是在
main
函数中,而我们通常把
main
函数放在源代码的最后。但是如果你尝试曾经描述过的一些关于函数的例子,可是把
main
函数放在了在其中调用的任何其他函数之前,你将很可能引发编译错误。它
的原因就是:如果要能调用一个函数,被调用函数必须在代码的更前面被声明过,就像我们在我们的例子中做的那样。
但是,有一可供选择的、不必把一个函数的全部代码在其能被在
main
或其他函数中使用前写下来的方法。这可以通过在其使用前仅仅声明这个函数的一个原型代替全部定义来实现。这个声明比全部实现要短,但是对编译器来说却足够其判断这个函数的返回值类型和这个函数的形参的类型。
它的格式是:
type name ( argument_type1, argument_type2, ...);
它和一个函数的定义是相同的,只是它不包含这个函数自身的函数体(如,在通常的定义中函数语句被用花括号
{}
括住)取而代之的是我们以一个分号(
;
)来结束原型声明。
形参列表不需要包含标示符,只需要类型说明符。在原型声明中对每一个形参,像在函数定义中那样包含一个标示符,是可选的。例如,我们可以用下边两种形式中的任何一种来声明一个带有两个
int
型形参的叫做
protofunction
的函数:
int protofunction (int first, int second);
int protofunction (int, int);
|
总之,每个变量包含一个名字是原型更易读。
// declaring functions prototypes
#include <iostream>
using namespace std;
void odd (int a);
void even (int a);
int main ()
{
int i;
do {
cout <<
"Type a number: (0 to exit) "
;
cin >> i;
odd (i);
} while (i!=0);
return 0;
}
void odd (int a)
{
if ((a%2)!=0) cout <<
"Number is odd./n"
;
else even (a);
}
void even (int a)
{
if ((a%2)==0) cout <<
"Number is even./n"
;
else odd (a);
}
|
Type a number (0 to exit): 9
Number is odd.
Type a number (0 to exit): 6
Number is even.
Type a number (0 to exit): 1030
Number is even.
Type a number (0 to exit): 0
Number is even.
|
这个例子很显然不是一个关于效率的例子。我确信在此时你已经能够编写一个能够得到相同结果,而代码行数只有例子中所使用的行数一半的程序了。但无论如何这个例子描述了原型是如何工作的。此外,在这个具体例子中:为了使编译代码没有错误,至少两个函数中的一个的原型是必须的。
我们看到的第一件事就是函数
odd
和
even
的声明:
void odd (int a);
void even (int a);
|
这就允许这些函数在它们定义之前就能被使用了,例如:在
main
中,现在
mian
被放在了一些人由于
main
是程序的开始,所以所认为的更加符合逻辑的地方:源代码的开始处。
总之,为什么这个程序需要至少一个函数被在它定义之前声明是因为在
odd
中有一个对
even
的调用,同样在
even
中有一个对
odd
的调用。如果这两函数都没有被提前声明,应该发生一个编译错误,因为既不能从
even
中看到
odd
(由于它还没有被声明),或从
odd
看到
even
(由于同样的原因)。
一些程序员发现把所有函数的原型放在源代码的同一个地方是有实用性的,这可以通过在一个程序的开始就声明所有函数的原型来实现。