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++有了沟通其它语言编写程序的能力,同时作为面向对象编程机制中的重要手段,在高级编程诸如动态链接库编程中都有广泛应用。