C++ 函数
来源:互联网 发布:简单java代码 编辑:程序博客网 时间:2024/06/02 02:49
函数的变化
正确的抽象机制要求你使用函数调用来隐藏实现代码。为了管理你将用到的所有函数,C++加强了对函数类型的要求。在使用函数之前,你必须声明它,包括它的参数类型。然而这里还有一定的灵活性,你可以赋予两个函数相同的名字,只要能够根据它们的参数将其区分开。
函数声明
函数声明(declaration)或称为函数原型(prototype)说明的是函数接口而不是函数主体。在C++或ANSI/ISO C 中,函数声明如下:
longfoo(char* a); //declaration of foo():takes char*, returns long
float bar(int, char); //declaration of bar(): takes int and char, returns float
它们由函数名、参数类型和返回值构成。参数类型是可选的。函数定义则指函数体:
int next(int i) {return i+1;} //definition ofnext()
所谓函数调用(invocation)也就是调用一个函数:
int main()
{
return next(5); //invocation of next()
}
函数声明就好像是维系函数调用和定义之间的桥梁。在C中,这个桥梁是可选的,编译器允许我们调用直到源代码中的某一点还没有声明(或真正定义)的函数。在C++中,一个函数在被调用之前一定要声明(或真正定义),否则编译器会报错。在函数调用之前必须先声明,这使得C++的编译器能够捕捉到C编译器可能错过的常见错误,例如错误的参数类型或拼写错误的函数名等。
C++和C在函数声明中表示控参数和没有限制的参数表时有所不同,如表2-1所示。
表2-1 C和C++中对空参数和没有限制的参数声明
意义
C
C++
空参数
f(void)
f() 或 f(void)
对参数没有限制
f()
f(…)
在C中,声明为f()的函数可以使用任何参数。要说明一个空的参数表,需将函数声明为f(void)。在C++中,前两种方式均表示空参数表。要说明没有限制的参数,需在函数声明中使用省略号,即f(…)。
参数产生的灵活性
为了减轻处理多个函数参数的负担,C++提供了三个技巧,它们在不同的时间内可以略去参数。我们前面已经提到过,在函数声明中参数名是可选的,对函数foo()来说就是这样:
intfoo(char* a); //these are equivalent declarations
int foo(char* );
在函数定义中你同样可以省略一个参数名。这会告诉编译器你并不打算使用那个参数。这里,draw3dpoint()的第三个参数是无用的:
voiddraw3dpoint(int x, int y, int) {
//thirdparameter has no name so the compiler knows we do //not use it
Draw2dpoint(x,y);
}
main(){draw3point( 1, 2, 7);} //arg still required in invocation
函数draw3point()大概暂时只使用它的前两个参数,并且调用函数draw2dpoint()。我们避免了使编译器给出警告,说第三个参数没有命名所以无法使用。这一技巧在程序开发的初始阶段是非常有用的,此时许多函数只不过是占位之用。
最后,函数还可以给参数赋缺省值。在调用函数时,你可以使用缺省的参数值而将其省略掉。这里,函数dist()的最后两个参数有缺省值:
double dist (int x1, int y1, int x2 = 0, int y2 = 0) {
//last two parameters have default values
return sqrt (sqr(x2-x1)+sqr(y2-y1)) };
main () {
double d1 = dist (1,2,3,4); //get distbetween (1,2) and (3,4)
double d2 = dist (1,2,3); //get dist between (1,2) and (3,0)
double d2 = dist (1,2); //get dist between (1,2)and (0,0)
}
函数dist()有四个参数,返回值是参数所代表的两个平面点之间的欧几里得距离。后两个参数的缺省值是0。在调用函数时我们提供的参数可以少于四个,如我们初始化d2和d3时所做的那样。
函数重载
一个函数的特征是函数名加参数的数量和类型。下面是函数foo的声明:
void foo(inta, int b);
它的特征是foo(int , char)。C++允许多个函数使用相同的名字,只要它们的特征不同即可:
voidfoo(int a, int b); //firstfoo
voidfoo(int a); //secondefoo
voidfoo(double a); //thirdfoo
main () {
foo(1,2); //calls the first foo
foo(1); //callsthe second foo
foo(.5); //calls the third foo
//…
}
链接
C++被设计成可以和传统的链接程序(linker)协同工作。传统的链接程序只知道函数名,而对它的参数类型却一无所知,因此它们不能检查你所传递的参数是否正确,更不懂得重载。为解决这些问题,C++在把函数名传递给链接程序之前会将它们替换为函数特征,这称为名字编码(name coding)。当你调用函数时使用的参数错误,或忘记对一个重载函数进行定义时,可能就会明白。链接程序可能会作如下提示:
Undefined sumbol: func_FPi3Foo
这可能是对函数func(int*, Foo)的编码。
C++允许你不使用名字编码,因此你可以链接到C编译器编译的代码上,这样做需要一个特殊声明extern:
extern “C” int func(int *, Foo);
这个函数传递给链接程序的名字中并没有被编码的参数类型。
这个例子给出了三个名为foo的函数,但是它们的特征不同。当编译器遇到函数调用foo()时,它就根据列出的参数数量和类型选择正确的函数。一个名字被多个函数使用称为重载(overload)。注意返回类型不是特征的一部分,你不能对两个除了返回类型不同其他都相同的函数进行重载,就像下面所示的两个函数:
voidfoo(int a, int b); //firstfoo
doublefoo(int a, int b); //error: samesignature as first foo
当一个函数调用中的参数类型和数量与某一个函数特征完全吻合时,那么调用哪个函数就不言而喻了。如果没有相匹配的函数,编译器会自动进行类型转换使调用和某个函数相匹配。自动类型转换时非常复杂和微妙的。例如:
voidbar(double d); //first bar
void bar(long l); //second bar
main () {
bar (3); //ambiguous because 3 is an int
//…
}
在上面的例子中,函数调用bar(3)中的参数是int型的,它与double和long都不匹配,编译器必须决定他们中的哪一个与int型更接近。在这个特殊的例子中,编译器会判断它们中的任何一个都不够接近int型,并且将调用报错函数。
我们建议精确地匹配你的参数,并且在必要的时候添加更多的重载函数。尽量避免类型转换,因为它们是危险的,但是如果你慎用它们,还是好过让编译器胡乱猜测自动转换类型的。这里,我们对bar()的每一个调用都是和它的一个定义恰好匹配的:
main () {
int I;
bar (3. 0); //calls first bar because 3.0 has type double
bar (3L); //calls second bar because 3L has type long
bar((long)i); //calls second bar because of cast
//…
}
严格的类型规则
除了加强函数的类型规则之外,c++还作了许多小的改变以在其他方面加强类型系统。严格的类型规则使得C++的编译器可以捕捉到许多bug,它们在C中可能会引起运行错误。本节中所讨论的改变的目的是防止类型的模糊性和类型系统的突变。C++仍然允许使用类型转换,这样就可以随意地避过这一规则。C++防止的是隐式类型转换,而不是显式类型转换。
Const
关键字const声明的值是不能被修改的:
Const int stone = 5; //stonecan never be modified
Int strlen (const char* s); //strlen()will not modify what s
//pointsto
这项规定对类型系统来说是极为有用的,你可能在C中已经使用过它了。使用const,你可以获得编译器的帮助以确认某个值没有改变。不幸的是,对初学者来说,const在C++中的意义和它在C中的有所不同。在C++中要正确地使用const也是非常复杂和微妙的。Void* : 通用指针
像C一样,C++允许你隐式地将一个指针转换为void* 型:
void *v;
Foo *f;
v = f; //implicit conversion to void*: ok inc and c++
在C和C++中, 我们都必须作类型转换就可以将Foo*型的指针f赋给void*型的指针v。C还允许你隐式地将void* 转换成其他任何类型的指针,但在C++中,你需要一个显式的类型转换:
f = v; // error in C++, ok in C: implicitconversion from void*
f =(Foo*)v; // ok in c++ and c:explicit cast from void*
C++在将v赋给f时要求作一个类型转换是因为对void*进行转换是不安全的,而且隐式变化的类型系统也是危险的。幸运的是,C++在很多情况下都省去了对void*的需要。- [C/C++]C函数
- c 函数
- C函数
- C 函数
- C函数
- 【C++】函数
- C 函数
- C++:函数
- C函数
- [C++]函数
- C函数
- c 函数
- C函数
- [C++]函数
- C函数
- 【c++】函数
- 【C++】函数
- C 函数
- Spring 的 BeanPostProcessor接口实现
- ubuntu 获取mysql.h文件时遇到问题的解决
- log4j输出多个自定义日志文件
- Objective-C语法property详解
- UML的时序图
- C++ 函数
- showModalDialog参数使用
- Objective-C语法之KVC的使用
- apache mina开发同步通信客户端
- 关于__init、__initdata和__exit、__exitdata的学习笔记
- DBLOAD
- A successful Git branching model
- SIG函数
- 使用python的logging模块