【C++再学习】【03】函数形参实参与值传递引用传递新解

       一开始没觉得这部分还需要整理一下,仔细看过书之后发现还有点意思,所以整理记录下来。根据传递方法的不同分成两大类整理,分别为继承自C的值传递以及C++新增的引用传递。

一、值传递

       先看两行再简单不过的代码:

        int a = 10;

        int b = a;

        这是用一个变量去给另一个变量赋值的代码,经过这种赋值后b可以随便改变自己的值,但是不影响a的值,我想说的是:函数的值传递方式的本质就是变量间的赋值。下边再给两个经典例子:

        void swap1(int a,int b)  

        {

         int temp = a;

          a = b;

         b = temp;

        }

        void swap2(int* a,int *b)

        {

         int* temp =a;

         a = b;

         b = temp

        }

        x=1,y=2;

        swap1(x,y);

        swap2(&x,&y);

        在调用swap1(x,y)函数的时候,我们知道这是典型的值传递,调用之后x,y的值并没有改变,但是在调用swap2(&x,&y)函数后,x,y的值发生了改变,这还是值传递么?答案是肯定的,这仍然是值传递,只不过这时赋值的是地址所以可以通过地址改变原有的参数值。可以看这样的两行代码:

        int a = 10;

       int * b = &a;

        这也是用一个变量去给另外一个变量赋值,只不过此时使用地址去赋值,所以任何通过b指针去改变它所指向地址的值时,a也会受到影响。

        所以,值传递的特点是:在函数调用时,系统会在函数作用域新建形参存储空间并用实参对其初始化,所以调用时形参是实参的一个副本。上面的swap1swap2函数都是典型的值传递方式。

二、引用传递

        首先说一下,引用是C++新增加的特性。同样,先看两行代码:

        int a = 10;

        int &b = a;

        此处的&符号并不是取地址的意思,而是声明ba的引用,俗话就是说ba的别名或者是代言人,b有什么变化就会同步到a上。函数的引用传递的本质就是这种引用赋值。下边再给个经典的例子:

        void swap3(int& a,int& b)

        {

         int temp = a;

         a = b;

         b =temp;

        }

        x=1,y=2;

        swap3(x,y);

        在调用swap3(x,y)之后x,y的值发生的变化,这就是引用传递,函数内部的ab成为xy的别名,任何对ab的更改都会同步到xy

三、值传递与引用传递的思考

        我们来对比一下两种传递方式:值传递需要复制实参内存内容以初始化形参,所以会带来一些开销,可能对于内置类型的参数开销可以忽略不计,但是对于大型的类对象来说,复制的代价会很大,虽然C语言也提供像上边swap2函数形式的“指针式”值传递方法,只传递过去一个地址,可以解决传递大的对象的复制开销问题,然而很多人对指针的安全问题一直都有很多看法。从这个角度出发,C++新提出了引用传递,可以达到“指针式”值传递的效果,同时不会带来很多安全问题。

四、普通形参、普通实参、const形参、const实参

        在函数的形参实参问题中,还有一些要注意的问题:

        先看这样一个例子:

        void fun(const int * p)

        {

            ......

        }

        int a = 10;

        const int b = 20;

        fun(&a);

         fun(&b);

        我们知道,如果不想让函数修改实参的值,我们可以将函数的形参定义为const类型,在上边代码中,用了两种实参类型去调用函数,一种是普通实参,一种是const实参,实际上这两种都是正确的。因为const指针既可以用普通的变量地址初始化,也可以用const变量地址初始化。

        再看看另外一个例子:

        void fun(int * p)

        {

            ......

        }

        int a = 10;

        const int b = 20;

        fun(&a);

        fun(&b);

        上边代码中函数形参为普通形参,而调用的时候用了两种类型实参,一种是普通变量a另一种是const变量b,前一种没有问题,后边这种实际上时错误的,编译器将禁止这种调用方式,也就是说不能用const实参去初始化普通形参,因为不能保证函数内部不会更改const实参的值。

         另外,有一些小提醒:

         1、在不希望函数内部修改实参时,尽量将函数的形参定义成const类型,这样一方面保证了实参不会发生变化,另一方面这种函数既可以接受const类型的实参调用又可以接受普通类型的实参调用,如果不用const形参那么将不能接受const实参类型调用,带来很多限制。

        2、有时候,我们希望函数不止有一个返回值,如果仅仅用return返回语句将不好实现,此时,可以在函数的形参列表中专门定义一个可以保存返回值的形参,一般定义为非const的引用类型或者指针类型,通过在函数内部给这样的这样的实参赋值就可以达到返回更多值得效果。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值