C++学习之引用、左值右值

  1. 引用定义
    1)引用即别名,就是某个变量的别名,对引用别名的操作与对变量本身完全相同.
    2)语法规则
    类型 & 引用名 = 变量名;
    注:引用在定义时必须初始化,初始化以后绑定的目标不能再改变。
    注:引用的类型与绑定的目标变量类型要相同。

  2. 常引用
    1)定义引用时加const修饰,即为常引用,不能通过常引用修改引用的目标。
    const 类型 & 引用名 = 变量名;
    类型 const & 引用名 = 变量名;
    以上两个通式,在有些情况下并不同。比如 const char * &rp;并不是应用类型为char *的常引用,而是引用类型为const char *的普通引用。若是想把const char * &rp声明为常引用,则应该采用第二个通式的方法,const char * const &rp;

    eg:
    int a = 10;
    const int& b = a;//b是a的常引用
    b++;//error
    a++;//ok
     
    2)普通引用也可以叫做左值引用,只能引用左值;而常引用也可以叫做万能引用,既可以引用左值,也可以引用右值。
     

  3. 引用型函数参数
    1)可以将引用用于函数的参数,这时形参将是实参的别名,可以通过形参直接修改实参变量,同时还可以避免参数值传递的过程,减小函数调用开销,提高代码执行效率。
    2)引用型参数有可能意外的修改实参,如果不希望修改实参本身,可以将参数定义为常引用,提高传参效率的同时还可以接收常量型的实参.
     
    引用作为参数

    #include <iostream>
    using namespace std;
    /*void swap1(int* x,int* y){
        *x = *x ^ *y;
        *y = *x ^ *y;
        *x = *x ^ *y;
    }*/
    void swap2(int& x,int& y){
        x = x ^ y;
        y = x ^ y;
        x = x ^ y;
    }
    void swap3(const char*& x,const char*& y ){
        const char* tmp = x;
        x = y;
        y = tmp;
    }
    int main(void){
        int a = 3;
        int b = 5;
        cout << "a=" << a << ",b=" << b << endl; 
        //swap1(&a,&b);
        swap2(a,b);
        cout << "a=" << a << ",b=" << b << endl; 
        //练习:使用引用参数,实现两个const char*字符串
        //的交换
        const char* s1 = "wangjl";
        const char* s2 = "yangjian";
        swap3(s1,s2);
        cout << "s1=" << s1 << endl;//yangjian
        cout << "s2=" << s2 << endl;//wangjl
    
        return 0;
    }
    

     

    #include <iostream>
    
    using namespace std;
    
    struct Teacher{
    	char name[128];
    	int age;
    	double sal;
    };
    
    void print(const Teacher* &t){
    	cout << t->name << "," << t->age << "," << t->sal <<endl;
    	t = NULL; //t不是常引用,t是普通引用(左值引用),如果是常引用,形参应该如下:
    		  //const Teacher * const & t;
    }
    
    int main(void){
    	Teacher wangjl = {"王建立", 45, 8000.5};
    	const Teacher *p = &wangjl;
    	print(p);
    	return 0;
    }
    
  4. 引用型函数返回值
    1)可以将函数的返回类型声明为引用,这时函数的返回结果就是return后面数据的别名,可以避免函数返回值所带来的的内存开销,提高代码执行效率.
    2)如果函数返回结果是一个普通(左值)引用,那么该函数调用表达式结果就也是左值.
    注:不要从函数中返回局部变量的引用,因为所引用的内存会在函数返回以后被释放,使用非常危险!但是可以从函数中返回成员变量、全局变量、静态变量的引用。

    #include <iostream>
    using namespace std;
    struct A{
        int data;
        int& func(void){
            return data;
        }
        int& func2(void){
            int num = 100;
            return num;//危险!
        }
    };
    int main(void){
        A a = {100};
        cout << a.data << endl;//100
        //a.data = 200
        a.func() = 200;//ok
        cout << a.data << endl;//200
    
        return 0;
    }
    
  5. 引用和指针
    1)从C语言角度看引用的实现,其本质就是指针,但是C++开发中推荐使用引用而不是指针.
    int i = 100;
    int* const pi = &i;
    int& ri = i;
    *pi <==> ri
    2)指针可以不做初始化,其指向的目标可以修改(指针常量除外);而引用必须初始化,一旦初始化其绑定目标的不能再修改.
    int a,b;
    int* p;//ok
    p = &a;//p指向a
    p = &b;//p指向b
     
    int& r;//error
    int& r = a;//r引用a,r就是a别名
    r = b;//ok,不是修改引用目标,仅是赋值操作
    &nbps;
    3)可以定义指针的指针(二级指针),但是不能定义引用的指针
    int a;
    int* p = &a;
    int** pp = &p;//ok,二级指针

    int& r = a;
    int&* pr = &r;//error,引用的指针
    int* pr = &r;//ok,但仅是普通指针
    4)可以定义指针的引用(指针变量的别名),但是不能定义引用的引用
    int a;
    int* p = &a;
    int* & rp = p;//ok,指针的引用

    int& r = a;
    int& & rr = r;//error,引用的引用
    int& rr = r;//ok,但仅是普通的引用
     
    5)可以定义指针数组,不能定义引用数组,但可以定义数组引用(数组的别名)
    int a=10,b=20,c=30;
    int* parr[3]={&a,&b,&c};//ok,指针数组
    int& rarr[3]={a,b,c};//error,引用数组,推理一下,很容易得出不合法:数组中,&arr[0],&arr[1],
    &arr[2]这三个地址,一定是连续的,但是如果是引用数组,&arr[0],&arr[1],&arr[2]等价于&a, &b, &c,这三个地址,不能保证是连续的。

    int arr[3] = {a,b,c};
    int (&rarr)[3] = arr;//数组引用
     
    6)和函数指针一样,可以定义函数引用(函数的别名),其语法特性和函数指针一致.
    void func(int a,int b){}
    int main(void){
    void (*pfunc)(int,int) = func;//ok,函数指针
    void (&rfunc)(int,int) = func;//ok,函数引用
    pfunc(…);
    rfunc(…);
    }

  6. 左值和右值
    左值(lvalue):可以放在赋值操作符左侧,可以被修改.
    –》普通变量
    –》前缀++、--
    –》赋值表达式结果
     
    右值(rvalue):只能放在赋值操作符右侧,不可以被修改
    –》字面值常量
    –》类型转换结果的临时变量
    –》加法(大多数、后++、–)表达式结果的临时变量
    –》函数中返回的临时变量

注:const int a = 100; 可以称a为不可修改左值

#include <iostream>
using namespace std;

int func(void){
    int num = 100;
    cout << "&num=" << &num << endl;
    return num;
}

int main(void){
    //int& r1 = 100;//error
    const int& r1 = 100;//ok
    cout << r1 << endl;

    char c = 'a';
    //首先要c转换为int类型,转换结果将保存到
    //临时变量,r2实际要引用是临时变量(右值)
    //int& r2 = (int)c;//error
    const int& r2 = (int)c;//ok
    cout << "&r2=" << &r2 << endl;
    cout << "&c=" << (void*)&c << endl;
    
    int a = 10;
    int b = 20;
    //加法表达式结果是临时变量(右值)
    //int& r3 = a+b;
    const int& r3 = a+b;
    cout << r3 << endl;//30

    int& r4 = ++a;//ok
    cout << r4 << endl;//11
    cout << &a << ',' << &r4 << endl;

    int& r5 = (a+=b);
    cout << r5 << ',' << a << endl;
    cout << &r5 << ',' << &a << endl;

    //函数返回结果不是return的num,而是return时
    //生成的临时变量(右值)
    //int& r6 = func();//error
    const int& r6 = func();//ok
    cout << r6 << endl;//100
    cout << "&r6=" << &r6 << endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值