1.函数接口的两个要素是参数和返回值。C语言中,函数的参数和返回值的传递方式有两种:值传递(pass by value)和指针传递(pass by pointer)。C++ 语言中多了引用传递(pass by reference)。由于引用传递的性质象指针传递,而使用方式却象值传递,初学者常常迷惑不解,容易引起混乱,
2.参数规则:
1)如果参数是指针,且仅作输入用,则应在类型前加const,以防止函数体内改动该指针指向的内容。(原文:以防止该指针在函数体内被意外修改。)
eg.
#include<iostream.h>
#include<assert.h>
#include<string.h>
void stringcpy(char *to,const char *from) //使用时保证from小于to指向的内存块
{
assert(from!=NULL&&to!=NULL);
// from[1]='y'; //编译错误。--l-value specifies const object--可见原文有误
while(*from!=0)
{
*to=*from;
to++;
from++;
}
*to=0;
}
void main()
{
char *f,*t;
f=new char[10];
t=new char[15];
// strcpy(t,"wo dslfjlsjflsjfldjsfljds"); //调用c库函数。运行错误。
stringcpy(f,"Hello");
stringcpy(t,f);
cout<<"f="<<f<<endl<<"t="<<t<<endl;
delete f;
delete t;
f=NULL;
t=NULL;
}
2)如果输入参数以值传递的方式传递对象,则宜改用“const &”方式来传递,这样可以省去临时对象的构造和析构过程,从而提高效率。
3.返回值规则:
1)不要将正常值和错误标志混在一起返回。正常值用输出参数获得,而错误标志用return语句返回。( 注:在c的库函数中有许多函数没有按此规则,使用不便)
4.内部实现规则
1)在函数体的“入口处”,对参数的有效性进行检查。
2)在函数体的“出口处”,对return语句的正确性和效率进行检查。
如:a)return语句不可返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。
b)如果函数返回值是一个对象,要考虑return语句的效率。
5.使用断言:程序一般分为Debug版本和Release版本,Debug版本用于内部调试,Release 版本发行给用户使用。断言assert是仅在Debug版本起作用的宏,它用于检查“不应该 ”发生的情况。
1)使用断言捕捉不应该发生的非法情况。不要混淆非法情况与错误情况之间的区别,后者是必然存在的并且是一定要作出处理的。
2)在函数的入口处,使用断言检查参数的有效性(合法性)。
3)在编写函数时,要进行反复的考查,并且自问:“我打算做哪些假定?”一旦确定了的假定,就要使用断言对假定进行检查。
6.引用与指针的比较(引用的主要功能是传递函数的参数和返回值。)
1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
2)不能有NULL引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。
4)如果的确只需要借用一下某个对象的“别名”,那么就用“引用”,而不要用“指针”,以免发生意外。比如说,某人需要一份证明,本来在文件上盖上公章的印子就行了,如果把取公章的钥匙交给他,那么他就获得了不该有的权利。
7.其他经验:
1)函数的功能要单一,不要设计多用途的函数。
2)函数体的规模要小,尽量控制在50行代码之内。
3)尽量避免函数带有“记忆”功能。相同的输入应当产生相同的输出。
带有“记忆”功能的函数,其行为可能是不可预测的,因为它的行为可能取决于某种“记忆状态”。这样的函数既不易理解又不利于测试和维护。在C/C++语言中,函数的static局部变量是函数的“记忆”存储器。建议尽量少用static局部变量,除非必需。
(学习林锐《高质量C++编程》笔记)2005/07/20