C++ Primer 学习笔记(六)——函数

一、函数的定义

1、求两个int型数的最大公约数

int gcd(int v1, int v2)
{
    while(v2){
        int temp = v2;
        v2 = v1 % v2;
        v1 = temp;
}

2、函数不能返回另一个函数或者内置数组类型,但可以返回指向函数的指针,或指向数组元素的指针。

3、函数形参表可以为空,但不可省略。若两个参数具有相同的类型,则其类型必须重复声明

二、参数传递之非引用形参

非引用形参表示对应实参的局部副本。对这类形参的修改仅仅改变了局部副本的值,不会修改实参的值。

1、普通形参类型

int gcd(int v1, int v2);


2、指针形参

(1)此时将复制指针实参。若函数将新指针值赋给形参,主调函数使用的实参指针的值没有改变

(2)如果函数形参是非const类型的指针,则函数可通过指针实现赋值,修改主调函数中指针所指对象的值。

(3)如需保护指针指向的值(主调函数中指针所指对象的值),则形参需定义为指向const对象的指针,如此一来,不能通过此指针修改其所指向的对象的值。

(4)根据初始化规则,可以将指向const对象的指针初始化为const对象或非const对象,但是,指向非const对象的指针只能指向非const对象。

3、const形参

(1)非引用的非const形参。既可以给该函数传递const实参,也可以传递非const的实参。(因为是非引用,所以仅仅是实参副本的传递)

(2)非引用的const形参。同样,既可以给该函数传递const实参,也可以传递非const实参。与(1)的区别仅仅在于,在被调函数中不可以改变形参(实参的局部副本)。

4、复制实参的局限性

有几种情况不适合复制实参:

(1)当需要在函数中修改实参的值时;

(2)当需要以大型对象作为实参传递时。对实际应用而言,复制对象所付出的时间和存储空间代价往往过大。

(3)当没有办法实现对象的复制时。

此时,应考虑将形参定义为引用或指针类型。

三、参数传递之引用形参

与其他所有引用一样,引用形参直接关联到其所绑定的对象,而并非这些对象的副本。

1、在三种情况下,应考虑将形参定义为引用类型:

(1)如果希望通过函数调用修改实参的值,就应该将形参定义为引用类型;

(2)若希望通过一次调用获得多个结果值,也可以使用引用形参;

(3)在向函数传递大型对象时,为了避免复制实参以提高效率,以及使用无法复制的类类型(其复制构造函数为private类型)作为形参类型时,也应该将形参定义为引用类型。

2、如果使用引用形参的唯一目的是避免复制实参(仅为1中的第三种情况,在被调函数中不需要修改引用形参),则应将引用形参定义为const引用。其原因在于:

非const引用形参只能与完全同类型的非const对象绑定;

const引用则可以绑定到不同但相关的类型的对象或绑定到右值

因此,普通的非const引用形参在使用时不太灵活。这样的形参既不能用const对象初始化,也不能用字面值或产生右值的表达式实参初始化。从而不必要的限制了该函数的使用。

3、传递指向指针的引用(不常用)

指向指针的引用就是指针的别名。例子:

void ptr_swap(int *&v1, int *&v2);


形参int *&v1的意义为:v1是个引用,与指向int型对象的指针绑定。

四、参数传递的其他情况

1、通常,函数不应该有vector或其他标准库容器类型的形参。调用含有普通的非引用vector形参的函数将会复制vector中的每一个元素,因此,应考虑将形参声明为引用类型。事实上,更倾向于通过传递指向容器中需要处理的元素的迭代器来传递容器

2、数组形参有三种定义:

void print_valu(int *);
void print_valu(int[]);
void print_valu(int[10]);


虽然不能直接传递数组,但是函数的形参可以写成数组的形式。以上三种定义是等价的,形参类型都是int *。

以上三种定义,第一种最好

最好不要在形参中指定数组长度,形参的长度会引起误解,而且编译器忽略为任何数组形参指定的长度

3、当不需要修改数组形参的元素时,函数应该将形参定义为指向const对象的指针。

4、如果形参是数组的引用,编译器不会将数组实参转换为指针,而是传递数组的引用本身。此时,数组大小成为形参和实参类型的一部分。由于形参是引用,在函数体中依赖数组大小是安全的。

int (&arr)[10];     //arr is a reference to an array of 10 ints.
int (*matrix)[10];  //pointer to an array of 10 ints.
int &arr[10];       //arr is an array of references.
int *matrix[10];    //array of 10 pointers.


5、有三种常见的编程技巧确保函数的操作不超出数组实参的边界:

(1)在数组本身放置一个标记来检测数组的结束。例子,C风格字符串,它是一种字符数组,并且以空字符'\0'作为结束的标记。

(2)传递指向数组第一个和最后一个元素的下一个位置的指针。

(3)将第二个形参定义为表示数组的大小。

五、return语句

1、不带返回值的return语句只能用于返回类型为void函数。在返回类型为void的函数中,return语句不是必需的。一般情况下,返回类型为void的函数使用return语句是为了引起函数的强制结束。

2、应该在含有return语句的循环后提供return语句。

3、为了使返回值独立于机器,cstdlib头文件中定义了两个预处理变量,EXIT_FAILURE和EXIT_SUCCESS,分别用于表示程序运行成功和失败。

4、返回非引用类型时,函数的返回值用于初始化在主调函数处创建的临时对象。

5、千万不要返回局部对象的引用,千万不要返回指向局部对象的指针

六、函数声明、局部对象与内联函数

1、通常,应该在函数声明中指定默认实参,并将声明放在合适的头文件中。

2、若有一个形参具有默认实参,那么,它后面所有的形参都必须有默认实参(因此,默认实参一般放在形参列表的尾部)

3、静态局部对象:位于函数的作用域内,但生命期却跨越了这个函数的多次调用的变量。此类变量即使不显式初始化,也会被初始化为0,且其初始化在整个程序执行期间仅进行一次

4、内联函数应该在头文件中定义。

七、类的成员函数

1、类的成员函数可以访问该类的private成员。编译器隐式的将在类内定义的成员函数当作内联函数。

2、每个成员函数(除了static成员函数外)都有一个额外的、隐含的形参this。在调用成员函数时,形参this初始化为调用该函数的类对象的地址。

3、const成员函数。在成员函数声明的形参表后面的const所起的作用:const改变了隐含的this指针的类型,this指针将是一个指向const对象的指针。因此,const成员函数不能修改调用该函数的对象。

4、const对象、指向const对象的指针或引用只能用于调用其const成员函数,如果尝试用它们来调用非const成员函数,则是错误的。

但是,非const对象、普通对象指针既可以调用其const成员函数,也可以调用非const成员函数

5、通常将类的声明放在头文件中,大多数情况下,在类外定义的成员函数应置于源文件中。

八、重载函数

1、函数不能仅仅基于不同的返回类型而实现重载。

2、对于非引用形参,形参与const形参是等价的。其原因在于实参传递的方式。函数操纵的只是副本。函数无法修改实参。

但是,有const引用形参的函数与有非const引用形参的函数是不同的。

3、每个版本的重载函数都应在同一个作用域中声明。

九、指向函数的指针(不常用)

1、函数的形参可以是指向函数的指针,也可以是函数;函数的返回值可以是指向函数的指针,但是不能是函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值