IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++中的引用 -> 正文阅读

[C++知识库]C++中的引用


前言

引用是变量的别名,本质是指针。

0x00 引用的初始化

引用必须初始化,而且不能初始化为常量。因为引用是定义一个指针,常量不能取地址。

int& p1; // error C2530: “p1”: 必须初始化引用

int& p2 = 0; // error C2440: “初始化”: 无法从“int”转换为“int &”

const引用可以初始化为常量
刚说完引用不能初始化为常量,结果const引用就可以初始化为常量,C++的语法真的是变化多端。

//int tmp = 0;  int* p3 = &tmp;
const int& p3 = 0;  

// 实际上自动生成一个局部变量保存0。
// 指针p3指向局部变量地址。

0x01 引用就是指针

void Swap(int* n1, int* n2) 
{
    cout << "void Swap(int* n1, int* n2)" << endl;
    int nTmp = *n1;
    *n1 = *n2;
    *n2 = nTmp;
}

void Swap(int& n1, int& n2) 
{
    cout << "void Swap(int& n1, int& n2) " << endl;
    int nTmp = n1; // int nTmp = *n1;
    n1 = n2;       // *n1 = *n2;
    n2 = nTmp;     // *n2 = nTmp;
}

int main(int argc, char* argv[])
{
    int n1 = 100;
    int n2 = 200;

    cout << "n1=" << n1 << "\tn2=" << n2 << endl;
    Swap(n1, n2);  // 反汇编中传递的是地址,说明实际上引用也是指针
    cout << "n1=" << n1 << "\tn2=" << n2 << endl;

    int n3 = 10;
    int n4 = 20;

    cout << "n3=" << n3 << "\tn4=" << n4 << endl;
    Swap(&n3, &n4);
    cout << "n3=" << n3 << "\tn4=" << n4 << endl;

    return 0;
}

程序输出结果:

n1=100  n2=200
void Swap(int& n1, int& n2)
n1=200  n2=100
n3=10   n4=20
void Swap(int* n1, int* n2)
n3=20   n4=10

两次调用Swap处的汇编代码:

    Swap(n1, n2);  // 反汇编中传递的是地址,说明实际上引用也是指针
004A109F 8D 45 E8             lea         eax,[n2]  
004A10A2 50                   push        eax  
004A10A3 8D 4D F4             lea         ecx,[n1]  
004A10A6 51                   push        ecx  
004A10A7 E8 29 54 FE FF       call        Swap (04864D5h)  
004A10AC 83 C4 08             add         esp,8 

004864D5 E9 E6 2D 01 00       jmp         Swap (04992C0h)

void Swap(int& n1, int& n2) 
{
004992C0 55                   push        ebp
	; 函数提升堆栈 开辟空间 略 
    cout << "void Swap(int& n1, int& n2) " << endl;
    ; cout的汇编略 
    int nTmp = n1; // int nTmp = *n1;
00499303 8B 45 08             mov         eax,dword ptr [n1]  
00499306 8B 08                mov         ecx,dword ptr [eax]  
00499308 89 4D F8             mov         dword ptr [nTmp],ecx  
    n1 = n2;       // *n1 = *n2;
0049930B 8B 45 08             mov         eax,dword ptr [n1]  
0049930E 8B 4D 0C             mov         ecx,dword ptr [n2]  
00499311 8B 11                mov         edx,dword ptr [ecx]  
00499313 89 10                mov         dword ptr [eax],edx  
    n2 = nTmp;     // *n2 = nTmp;
00499315 8B 45 0C             mov         eax,dword ptr [n2]  
00499318 8B 4D F8             mov         ecx,dword ptr [nTmp]  
0049931B 89 08                mov         dword ptr [eax],ecx  
}
	; 函数平衡堆栈 返回 略



    Swap(&n3, &n4);
004A1141 8D 45 D0             lea         eax,[n4]  
004A1144 50                   push        eax  
004A1145 8D 4D DC             lea         ecx,[n3]  
004A1148 51                   push        ecx  
004A1149 E8 D5 5A FE FF       call        Swap (0486C23h)  
004A114E 83 C4 08             add         esp,8

00486C23 E9 28 27 01 00       jmp         Swap (0499350h)

void Swap(int* n1, int* n2) 
{
00499350 55                   push        ebp  
	; 函数提升堆栈 开辟空间 略  
    cout << "void Swap(int* n1, int* n2)" << endl;
    ; cout的汇编略 
    int nTmp = *n1;
00499393 8B 45 08             mov         eax,dword ptr [n1]  
00499396 8B 08                mov         ecx,dword ptr [eax]  
00499398 89 4D F8             mov         dword ptr [nTmp],ecx  
    *n1 = *n2;
0049939B 8B 45 08             mov         eax,dword ptr [n1]  
0049939E 8B 4D 0C             mov         ecx,dword ptr [n2]  
004993A1 8B 11                mov         edx,dword ptr [ecx]  
004993A3 89 10                mov         dword ptr [eax],edx  
    *n2 = nTmp;
004993A5 8B 45 0C             mov         eax,dword ptr [n2]  
004993A8 8B 4D F8             mov         ecx,dword ptr [nTmp]  
004993AB 89 08                mov         dword ptr [eax],ecx  
}
	; 函数平衡堆栈 返回 略

两次Swap调用时的汇编与两个Swap实现的汇编,完全相同。由此说明,引用就是指针。
并且还说明,引用也可以作为函数重载的条件。

0x02 指针的引用

基本类型的引用用来接收基本类型变量
指针类型的引用用来接收指针类型变量。

int main(int argc, char* argv[])
{
    int n1 = 100;
    int& ppp = n1;

    //int*& p1 = &n1; //error C2440: “初始化”: 无法从“int *”转换为“int *&”

    // p2保存p的地址。可以通过p2修改p的值,也就是修改p的指向
    int* p = nullptr;
    int*& p2 = p;  // 可以通过

    int* const pc = nullptr;
    // 不可以通过,因为尽管p3保存pc的地址,但是不能通过p3的值修改pc
    //int*& p3 = pc; // error C2440: “初始化”: 无法从“int *const ”转换为“int *&”

    return 0;
}

交换两个指针:

void SwapPointer(int*& n1, int*& n2) 
{
    int* tmp = n1;
    n1 = n2;
    n2 = tmp;
}

0x03 引用作为参数

引用作为参数时传递的是变量的地址

引用不能初始化为常量,因此不能用常量参数调用参数为引用的函数。
const引用可以初始化为常量。可以用常量作为参数调用参数为const引用的函数。

void show(const int& n1, const int& n2) 
{
    cout << n1 << endl;
    cout << n2 << endl;
}

void show(int& n1, int& n2) 
{
    cout << n1 << endl;
    cout << n2 << endl;
}

int main(int argc, char* argv[])
{

    show(1, 2); // void show(const int& n1, const int& n2)

    int n1 = 10;
    int n2 = 20;


    // 如果没有void show(int& n1, int& n2),
    // 才会调用void show(const int& n1, const int& n2)
    show(n1, n2);

    return 0;
}

当有参数为引用的函数和参数为const引用的函数时调用规则:

变量作为实参时,如果都存在会优先使用引用,如果引用不存在,才会使用const引用。
常量作为实参时,只能使用const引用

0x04 引用作为参数的二义性

void show(int& n1, int& n2) 
{
    cout << n1 << endl;
    cout << n2 << endl;
}

void show(int n1, int n2) 
{
    cout << n1 << endl;
    cout << n2 << endl;
}

int main(int argc, char* argv[])
{
    int n1 = 10;
    int n2 = 20;
    // error C2668: “show”: 对重载函数的调用不明确
    //show(n1, n2);

    show(1, 2); // void show(int n1, int n2)

    return 0;
}
void show(const int& n1, const int& n2) 
{
    cout << n1 << endl;
    cout << n2 << endl;
}

void show(int n1, int n2) 
{
    cout << n1 << endl;
    cout << n2 << endl;
}

int main(int argc, char* argv[])
{
	// error C2668: “show”: 对重载函数的调用不明确
    //show(1, 2);

    int n1 = 10;
    int n2 = 20;

    // error C2668: “show”: 对重载函数的调用不明确
    //show(n1, n2);

    return 0;
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-22 20:23:18  更:2022-02-22 20:25:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:26:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码