对函数传入,是指用实参将外部数据传给函数,以便于在函数体内对其处理。
对函数传出,是指用返回值将函数处理的结果交给主调函数。
设计函数时要考虑到:
1、函数是否担负修改实参的任务?
2、传入实参是否会影响效率?
3、形参是否还要承担向调用者传递部分结果的任务?
关注函数的返回值:
当它是变量或对象时,一切OK。因为返回值是局部变量的复制品。但若返回值是地址或引用,则要引起足够的警惕。关注:
1、这个地址是局部变量的吗?
2、这个地址是由函数malloc()或new产生的?
3、这个地址是形参传进来的吗?
4、是全局变量的地址吗?
5、是静态变量的地址吗?
若是4或5,则无事;若是1,则错了!若是2,则要追踪其何时释放;若是3,则要看形参自身是指针,则可以,若形参不是指针,则错。
函数返回的可以是:
1、变量的值(无论局部还是全局);
2、静态局部变量的值或址;
3、静态局部数组的址;
4、全局变量的值或址;
5、全局数组的址;
6、堆空间的地址;
注意:函数返回类型是指针时的模糊性
函数的返回类型可以是指针。比如,用于在数组中查找某值的函数,通常做成“当查到时,返回指向该元素的指针;查不到时,返回NULL指针。”
这种“用一个值表示两种不同含义”的做法很危险。因为它加重了使用函数者的负担。若查找的元素的值就是NULL怎么办?
好的设计是让函数的返回只担负一个职责:是否找到。将查找到的元素地址用函数的形参指针传递。
一些结论:
1、函数调用只能用于非静态局部变量的初始化。
2、静态变量作形参,失去了静态性
子函数的构造原则:
一个函数应具有的强壮性体现在两个方面:
1、对传来的实参不能无条件地接受,要进行合法性验证,不要基于“实参都是对的”的懒惰惯性思维,要学会拒绝;
2、函数体内的处理过程也要时时进行合理性检查,要由容错处理(异常处理)机制,一旦有错不但会报警,还要有全身而退的对策。因为程序是在有限资源的空间上运行的。
通常由三种处理方法:
1)最极端的做法就是用exit(-1)函数,粗暴的终止程序,这无异于谋杀;
2)用抛掷异常的现代手段;
3)让子函数温和地停止,并返回一个真假值,此法能使程序不致夭折,将决定权交由调用者酌情处理。此谓全身而退策略。
函数指针的意义:
1、历史的原因,函数类型不能做参数,语言将自动将转换为函数指针。
2、通过函数指针可以使C++语言使用其他语言写就的函数。
3、通过函数指针参数尅使主调函数得到不同的被传入的函数,于是可以表现出多种行为。
4、函数指针使虚函数得以实现。
5、通过函数指针可以括约本地进程,访问其他进程。
6、函数指针使函数设计更加变幻莫测,会偏离函数的黑盒性。
7、函数可以定义引用。
函数指针有它的一个致命的缺点:
无法对参数和返回值的类型进行检查,因为函数已经退化成指针,指针是不带有这些类型信息的。少了类型检查,当参数或者返回值不一致时,会造成严重的错误。