0
点赞
收藏
分享

微信扫一扫

C++中的引用

古得曼_63b6 2022-02-21 阅读 91
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引用的函数时调用规则:

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;
}
举报

相关推荐

0 条评论