前言
引用是变量的别名,本质是指针。
0x00 引用的初始化
引用必须初始化,而且不能初始化为常量。因为引用是定义一个指针,常量不能取地址。
int& p1;
int& p2 = 0;
const引用可以初始化为常量 刚说完引用不能初始化为常量,结果const引用就可以初始化为常量,C++的语法真的是变化多端。
const int& p3 = 0;
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;
n1 = n2;
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* p = nullptr;
int*& p2 = p;
int* const pc = nullptr;
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);
int n1 = 10;
int n2 = 20;
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;
show(1, 2);
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[])
{
int n1 = 10;
int n2 = 20;
return 0;
}
|