C++中的const用法【02】----函数的参数和返回值

如果按值传递对象,它意味着传递的参数在函数中是不能被修改的。

如果按常量返回用户定义类型的对象的值,这意味着返回值不能被修改。

如果传递参数并返回地址,const 将保证改地址不会被改变。


1. 传递const  值

如果参数是按值传递,那么可用const 修饰指定参数。

void fun1(int value1 , const int value2) {
        value1 ++ ; // Safe
        value2 ++ ; // Error ,被const 修饰的变量不能被更改
}

这里有一个规定,就是value2已被const 修饰,在fun1()函数的整个生命周期中,value2都无法被修改。由于采用的是按值传递,因此fun1()在这里会定义2个实参的副本作为形参,并将第二个形参设置为const 对象。

const 在函数中的用法很简单,就是将一个对象修饰成“无法被修改的”,因此可以将它试做被调的工具而非主调的。(因为上述过程对于主调来说是不知情的)

为了使得程序更加清晰,最好将const 限定参数放在函内部而非它的参数列表,这样可以使得被调的形参列表与主调相同。

#include <iostream>
using namespace std ;

void fun(int value1) {
        const int& i = value1 ;
        i ++ ;          //Error,i is a const object;
<span style="white-space:pre">	</span>value ++ ;      
}

int main (void) {
        int a = 1 , b = 2 ;
        fun(a) ;
        return 0 ;
}


我们可以借助引用,让const 限定参数这一过程在函数内部实现,但需要注意的是,在内部实现的情况下,我们定义的引用变量是const 的,但形参依然是非const ,这意味着形参依旧可以被改变。因此,我们一旦使用了引用去实现,在接下来的描述中,要尽量使用const 修饰的引用变量而非原参数。



2. 返回const 值


对函数的返回值而言,const 也有类似的功能:将一个函数的返回值限定为常量。

其声明形式如下:

const int fun() ;
这样的形式会使得函数框架中原变量不会修改。

#include <iostream>
using namespace std ;

int fun3() {
        return 1 ;
}

int fun4() {
        return 2 ;
}

int main (void) {
        const int i = fun3() ;  //It is safe ;
        int j = fun4() ;        //It is also safe ;
        return 0 ;
}

对于内建类型(int , double , char等)而言,按值返回的对象是否是一个const ,都无关紧要,因为它返回的是仅仅一个值,就如同 

const int i = 0 ;
int j = i ;
一样,是一个简单的赋值过程,因此对于主调的接收值类型来说,有没有const 都可以。但在没有必要时最好不要带上,不然容易引起混淆。


而当处理用户自定义的类型(struct,class)时,按值返回常量却是非常重要的,如果一个函数按值返回一个类类型的const 对象时,那么这个函数的返回值就不能作为一个左值(即不能出现在等号左边,不能被赋值或被修改)


#include <iostream>
using namespace std ;

class Example {
private:
        int i_ ;
public:
        Example(int i) : i_(i) {}
        void modify() {
                i_ ++ ;
        }
        // default constructor
        ///~
        // copy constructor
        ///~
};

Example fun1() {
        return Example() ;
}

const Example fun2() {
        return Example() ;
}

int main(void) {
        fun1() = Example(1) ;   //safe
        fun1().modify() ;       //safe
        fun2() = Example(1) ;   //error , fun2的返回值类型是const Example , 即返回的对象不能被改变
        fun2().modify() ;       //error , const对象不能调用非const成员函数
        return 0 ;
}


<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"><span style="white-space:pre">	</span>fun1()返回一个非const 对象,而fun2()返回一个const 对象,只有非const返回值能作为一个左值引用。当按值返回一个类对象时,如果不希望这个类对象被改变,就请大家使用const 来修饰。</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">
</span>
总结:在按值传递内建类型时,const 没有意义的原因是,编译器已经成功的阻止它成为左值,因为这样的函数返回的是一个值,而不是一个变量,一个值只能被其他对象接收,而不能被更改。因此,只有按值返回一个用户定义的类类型时,const 的修饰才会变得不可或缺。


3. 传递和返回地址

如果传递或返回一个地址,那么其处置可能被通过操纵地址所改变,使用const 修饰可以有效的阻止这类事情的发生。并且,无论什么时候将地址传递给函数,都英爱尽可能的使用const 去限制。


#include <iostream>
using namespace std ;

void fun1(int *) {}

void fun2(const int * cip) {
        * cip = 2 ;             //error,const int * 是限制指针所指向的值不能被改变,因此无法赋值
        int i = * cip ;         
        int * cp2 = cip ;       //error,不能将const int * 赋值给int * ;
}

const char * fun3() {
        return "result of fun3()" ;
}

const int * const fun4() {
        static int i ;
        return &i ;
}

int main(void) {
        int x = 0 ;
        int * ip = &x ;
        const int * cip = &x ;      
        fun1(ip) ;                      
        fun1(cip) ;                     
        fun2(ip) ;                              //!!error,不能用int * 赋值给const int *
        fun2(cip) ;                     
        char * cp = fun3() ;                    //!!error,不能用const char * 赋值给char *
        const char * ccp = fun3() ;     
        int * ip2 = fun4() ;                    //!!error,不能用const int * const 赋值给int *
        const int * const ccip = fun4() ;       
        const int * cip2 = fun4() ;            <span style="color:#ff0000;"> //特别强调,这个是正确的,可以将const int * const 赋给const int * ;
        //因为const int * const 和 const int *都表示指针的指向被const修饰不能随意改变,这回与函数来说已经足够了
        //它指向的值是不是const编译器都不会再去判断,因为接下来执行的是赋值过程
        //就像我们刚才说的,对于按值传递的内建类型的返回值常量有无const修饰都没有太大区别</span>
        *fun4() = 1 ;                           //!!error,返回的指针本身和它所指向的对象都无法更改,因此不能作为左值
        return 0 ;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值