C++学习笔记(重温计划之六)
4、函数性质
1)函数形态
C++中的函数分为“求值”和“返回值为空”两种类型。当函数有返回值时,须定义函数的返回值类型,为空时须定义为void。理论上说,函数只对输入参数和输出返回值负责,至于函数内部的细节程序本身并不干预。编程的原则是优先调用c++库函数,而后再进行手写,这有助于提升编程效率。
2)传值参数
参数通过传值机制进入函数内部。传值的具体方法是,在程序中遇到函数被调用时,实参被克隆为形参并参加函数运算。须注意的是,参数个数不宜过多。
3)指针参数
在面向对象编程中,我们通常使用指针参数的形式来进行传参。这样的好处是,指针参数其实赋予了函数操作异地数据的能力,使得函数不再需要返回具体值,而已经在函数运行中产生结果了。我们给出一个传递数组的方法:
void mySort (int* b,int size);
void f(){
int a[]={3,4,5,1,7,2,9};
mySort(a,sizeof(a)/sizeof(a[0]));
//…
}
而事实上,数组也就只能使用传递地址一种方法来达到传递的目的。在实际编程中,传递指针和引用的特性广受欢迎。但是,传递指针和引用在一定程度上破坏了函数的黑盒性,不排除造成灾难性错误的可能,这就引起了一些麻烦。当然我们也可以利用一些手段来避免此类问题,例如:当传递引用时,使用const修饰符限制函数对参数的操作等等。
4)函数的栈机制
一般情况下,每当一个程序要运行时,操作系统会自动在内存中生成一个随时可以运行的进程空间。空间中分四个区域,分别是代码区、全局数据区、堆区和栈区。在栈区中,动态地存放了程序运行中的函数状态,利用这一点,我们可以进一步研究函数机制。
平时在编写函数时,我们会给局部变量赋初值。这是因为c++的栈机制决定的。由于系统并不存在所谓的清理机制,每当运行一个新的程序时,旧的栈区中的数据将保留下来,而未得到初值的变量也就无可奈何了。
以上也同样展现了指针的负面效应,甚至当我们知道数据确切地存放地址时,就可以任意而直接地改变地址中的数值了。
5)函数指针
函数指针主要有以下几种声明方法:
int* f(int a);
int *gp(int) ;
int g(int); //这是另一种声明和定义区分开的例子
int (gp)(int) =g; //我们可以写成 int (gp)(int); int gp =g;
需要注意,在声明或定义函数指针时,其参数的类型须为一致,否则编译不能通过。函数指针的主要作用是用来进行参数传递,且一般为bool(const T&,const T&)形式。在函数指针数组中,一些特定的操作将被简化和易于维护,例如:
//…
typedef void (*MenuFun)();
MenuFun fun[] = {f1,f2,f3};
cin>>choice;
switch(choice){
case 1:fun0;break;
//…
}//…
函数指针还使得C++有了沟通其它语言编写程序的能力,同时作为面向对象编程机制中的重要手段,在高级编程诸如动态链接库编程中都有广泛应用。