从C到C++入门篇(三)引用;引用的本质

Reference & 引用

变量名,本身是一段内存的引用,即别名(alias)。此处引入的引用,是为己有变
量起一个别名。

int a= 500; //变量名.实质是一段内存空间的别名

(int)0x0002345=500;

引用的规则

  1. 引用,是一种关系型声明,而非定义。
    不能独立存在,必须初始化,且与原类型保持一致,且不分配内存。
  2. 声明关系,一经声明,不可变更。
  3. 可对引用,再次引用。多次引用的结果,
    是某一变量具有多个别名,多个别名间是平行关系。
  4. 辨别引用与其它,&符号前有数据类型时,
    是引用,其它皆为取地址或按位与。
#include <iostream>
using namespace std;
int main()
{
    int a,b;
    int &ra = a; //声明引用变量 ra,并初始化为 a 变量的引用
//    int &ra = b; //错误,不可更改原有的引用关系
//    float &rb = b; //错误,引用类型不匹配
    cout<< sizeof(a)<<"  "<< sizeof(ra)<<endl; // 4  4
    cout<<&a<<"  "<<&ra<<endl;  //变量与引用具有相同的地址。//0x62fe0c  0x62fe0c
    a=100;
    cout<<a<<"  "<<ra<<endl;//100  100
    ra=200;
    cout<<a<<"  "<<ra<<endl;//200  200

    int &rra = ra; //可对引用再次引用,但是不能建立引用的引用 (int & &rra = ra; 是错误的)
    // 表示 a 变量有两个别名,分别是 rra 和 ra
    cout<<a<<"  "<<ra<<"  "<<rra<<endl;//200  200  200
    cout<<&a<<"  "<<&ra<<"  "<<&rra<<endl;  //变量与引用具有相同的地址。//0x62fe0c  0x62fe0c  0x62fe0c


    int *p = &ra; //可以对引用取地址,但是不能建立引用的指针 (int & *p=&ra; 是错误的) 引用的本质是对指针的包装,再对其解包没有意义
    cout<<p<<"  "<<&ra<<"  "<<&rra<<endl; //0x62fe04  0x62fe04  0x62fe04

    return 0;
}

引用的应用

交换数据:

#include <iostream>
using namespace std;

void swap(int &a, int &b){
    a^=b;
    b^=a;
    a^=b;
}

int main()
{
    int a=5, b=10;
    cout<<"交换前: a="<<a<<" b="<<b<<endl;
    swap(a, b);
    cout<<"交换后: a="<<a<<" b="<<b<<endl;
    return 0;
}

交换前: a=5 b=10
交换后: a=10 b=5

交换指针:

#include <iostream>
using namespace std;

//交换指针 引用的本质是对指针的再次包装 ; 指针是有引用的 ; 不应该有引用的指针
void swap(char* &p, char* &q){
    char* temp=p;
    p=q;
    q=temp;
}
int main()
{
    char* pchar="hello";
    char* qchar="world";
    cout<<"交换前: pchar="<<pchar<<" qchar="<<qchar<<endl;
    swap(pchar, qchar);
    cout<<"交换后: pchar="<<pchar<<" qchar="<<qchar<<endl;

    return 0;
}

交换前: pchar=hello qchar=world
交换后: pchar=world qchar=hello

深入使用引用

引用的本质是指针,C++对裸露的内存地址(指针)作了一次包装。又取得的指针的优良特
性。所以再对引用取地址,建立引用的指针没有意义。

  1. 可以定义指针的引用,但不能定义引用的引用。
    int a;
    int* p = &a;
    int*& rp = p; // ok
    int& r = a;
    int&& rr = r; // error
    
    引入引用的目的,将问题控制在变量的层次上,而不是提升层次. (消灭指针)
  1. 可以定义指针的指针(二级指针),但不能定义引用的指针。
    int a;
    int* p = &a;
    int** pp = &p; // ok
    int& r = a;
    int&* pr = &r; // error  r本质是对指针深层次的包装!
    
    int * & ==> 指针的引用
    int & * ==> 引用的指针
  1. 可以定义指针数组,但不能定义引用数组,可以定义数组引用。
    int a, b, c;
    int* parr[] = {&a, &b, &c}; // ok
    int& rarr[] = {a, b, c}; // error 不能定义引用数组
    //rarr 代表首元素地址;数组中元素是 int& ,rarr代表int & * ,int & *是引用的指针,不被允许的
    
    
    int arr[] = {1, 2, 3};
    //arr代表首元素地址;数组名等价于int[3] ;对他引用 int[3] & ; 本质int * & ==> 指针的引用
    
    int (&rarr)[3] = arr; // ok 可以定义数组引用
    本质是:int[3] &rarr = arr;

常引用

const 引用有较多使用。它可以防止对象的值被随意修改。因而具有一些特性。

     const int a=10;
    //&a;  //取地址a 取出==> const int *
    //int * p=&a; //c++中是不允许的
    const int * p=&a; //正确的写法

    //int &ra=a; //依然不允许
    const int &ra=a; //正确的写法
  1. const 对象的引用必须是 const 的,将普通引用绑定到 const 对象是不合法的。 这
    个原因比较简单。既然对象是 const 的,表示不能被修改,引用当然也不能修改,必须使
    用 const 引用。实际上,const int a=1; int &b=a;这种写法是不合法的,编译不过。
  2. const 引用可使用相关类型的对象(常量,非同类型的变量或表达式)初始化。这个是
    const 引用与普通引用最大的区别。const int &a=2;是合法的。double x=3.14; const int
    &b=a;也是合法的
    const int x=10;
    const int &rx=x; //正确

    int y=10;
    const int &rx=y; //正确
    
    
    int a=10;
    double &ra=a; //error 引用的类型,必须于被引用的类型一致
    const double &ra=a; //使用const 就可以
    
    int &rr=a+6; //error
    const int &rr=a+6; //使用const 就可以

    const int & rv=200;//正确 常量可以赋值
    
    
    
void func(const int & rv ){}
    func(200); //正确 
    func(a+200);//正确 表达式可以赋值

引入一段代码解读const

#include <iostream>
using namespace std;
int main()
{
    int a=200;
    int & ra = a;
    //double & rd = a;  //不加const编译不过的
    const double & rd = a;

    a = 300;
    cout<<"a = "<<a<<endl;//输出:a = 300
    cout<<"ra = "<<ra<<endl;//输出:ra = 300
    cout<<"rd = "<<rd<<endl;//输出了:rd = 200

    cout<<"打印地址"<<endl;
    cout<<"&a = "<<&a<<endl;// &a = 0x62fe04
    cout<<"&ra = "<<&ra<<endl;// &ra = 0x62fe04
    cout<<"&rd = "<<&rd<<endl;// &rd = 0x62fe08


    return 0;
}

实际上,const 引用使用相
关类型对象初始化时发生了如下过程:

const double & rd = a;
其中
double temp=a;
const double & rd = temp;

此时产生了与表达式等值的无名的临时变量,
此时的引用是对无名的临时变量的引用。故不能更改。
const使用了中间变量存储,中间变量是绝对不能更改的;

尽可能使用 const

1,使用 const 可以避免无意修改数据的编程错误。

2,使用 const 可以处理 const 和非 const 实参。否则将只能接受非 const 数据。

3,使用 const 引用,可使函数能够正确的生成并使用临时变量(如果实参与引用参数不匹配,就会生成临时变量)

引用的本质浅析

引用的特性显示引用是: int * const p; 是一个const修饰的指针

#include <iostream>
using namespace std;
struct TypeP
{
    char *p;
};
struct TypeC
{
    char c;
};
struct TypeR
{
    char& r; //把引用单列出来,不与具体的对像发生关系
};


int main()
{

    printf("%d %d %d\n",sizeof(TypeP),sizeof(TypeC),sizeof(TypeR));
    //输出结果为:8 1 8
    //引用的特性显示引用是: int * const p; 是一个const修饰的指针

    return 0;
}

反汇编对比指针和引用

原程序:

#include <iostream>
using namespace std;
void Swap(int *p, int *q)
{
    int t = *p;
    *p = *q;
    *q = t;
}
void Swap(int &p, int &q)
{
    int t = p;
    p = q;
    q = t;
}
int main()
{
    int a = 3; int b =5;
    Swap(a,b);
    Swap(&a,&b);
    return 0;
}

汇编程序:
在这里插入图片描述

  • 26
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可能只会写BUG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值