指针和引用¶
1 指针和引用的区别¶
很多情况直接替换就可以,引用就是静态指针实现的
* 不存在空引用。指针不用
* 引用只能连接到一块内存,无法修改。指针不用
* 引用创建后必须初始化。指针不用
* 自增自减时引用是值,指针是地址。
2 指针¶
指针是一个变量,其值为另一个变量的地址。
- 定义一个指针变量
- 把变量地址赋值给指针
- 访问指针变量中可用地址的值。
3 引用¶
给一个已经定义好的变量去个别名。
int main() {
int a = 10;
int &b = a;
int &c = b;
std::cout << "a: " << &a << " " << a << std::endl;
std::cout << "b: " << &b << " " << b << std::endl;
c = 100;
std::cout << "a: " << &a << " " << a << std::endl;
std::cout << "b: " << &b << " " << b << std::endl;
std::cout << "c: " << &c << " " << c << std::endl;
}
a: 0000002106D8FD80 10
b: 0000002106D8FD80 10
a: 0000002106D8FD80 100
b: 0000002106D8FD80 100
c: 0000002106D8FD80 100
4 作为参数¶
指针和引用作为参数传入函数一样,都是:隐式的返回传递值
void Quote(int &x) {
std::cout << "x: " << &x << " " << x << std::endl;
x++;
std::cout << "x: " << &x << " " << x << std::endl;
}
void Pointer(int *x) {
std::cout << "x: " << &x << " " << x << " " << *x << std::endl;
x[0]++;
std::cout << "x: " << &x << " " << x << " " << *x << std::endl;
x++;
std::cout << "x: " << &x << " " << x << " " << *x << std::endl;
}
void Normal(int x) {
std::cout << "x: " << &x << " " << x << std::endl;
x++;
std::cout << "x: " << &x << " " << x << std::endl;
}
int main() {
int a = 10;
std::cout << "a: " << &a << " " << a << std::endl;
std::cout << "Quote-----------" << std::endl;
Quote(a);
std::cout << "a: " << &a << " " << a << std::endl;
std::cout << "Pointer-----------" << std::endl;
Pointer(&a);
std::cout << "a: " << &a << " " << a << std::endl;
std::cout << "Normal-----------" << std::endl;
Normal(a);
std::cout << "a: " << &a << " " << a << std::endl;
}
a: 000000B7B8CFF8B0 10
Quote-----------
x: 000000B7B8CFF8B0 10
x: 000000B7B8CFF8B0 11
a: 000000B7B8CFF8B0 11
Pointer-----------
x: 000000B7B8CFF8B8 000000B7B8CFF8B0 11
x: 000000B7B8CFF8B8 000000B7B8CFF8B0 12
x: 000000B7B8CFF8B8 000000B7B8CFF8B4 0
a: 000000B7B8CFF8B0 12
Normal-----------
x: 000000B7B8CFF8B8 12
x: 000000B7B8CFF8B8 13
a: 000000B7B8CFF8B0 12
结论:建议使用引用,看着舒服,而且效率高一些。
翻译成汇编后,指针传递比参数多一个创建变量。
1_17!Quote [f:\studyc\1-17\main.cpp @ 13]:
0x7ff7534f2a60 mov qword ptr [rsp+8],rcx
0x7ff7534f2a65 <+ 5> push rdi
0x7ff7534f2a66 <+ 6> mov rax,qword ptr [rsp+10h]
0x7ff7534f2a6b <+ 11> mov eax,dword ptr [rax]
0x7ff7534f2a6d <+ 13> inc eax
0x7ff7534f2a6f <+ 15> mov rcx,qword ptr [rsp+10h]
0x7ff7534f2a74 <+ 20> mov dword ptr [rcx],eax
0x7ff7534f2a76 <+ 22> pop rdi
0x7ff7534f2a77 <+ 23> ret
1_17!Pointer [f:\studyc\1-17\main.cpp @ 17]:
0x7ff7534f2a80 <+ 32> mov qword ptr [rsp+8],rcx
0x7ff7534f2a85 <+ 37> push rdi
0x7ff7534f2a86 <+ 38> mov eax,4
0x7ff7534f2a8b <+ 43> imul rax,rax,0
0x7ff7534f2a8f <+ 47> mov rcx,qword ptr [rsp+10h]
0x7ff7534f2a94 <+ 52> mov eax,dword ptr [rcx+rax]
0x7ff7534f2a97 <+ 55> inc eax
0x7ff7534f2a99 <+ 57> mov ecx,4
0x7ff7534f2a9e <+ 62> imul rcx,rcx,0
0x7ff7534f2aa2 <+ 66> mov rdx,qword ptr [rsp+10h]
0x7ff7534f2aa7 <+ 71> mov dword ptr [rdx+rcx],eax
0x7ff7534f2aaa <+ 74> pop rdi
5 常引用¶
常引用无法修改变量本身的值。使用引用作为参数传入效率高
引用型参数应该在能被定义为 const 的情况下,尽量定义为 const。
6 作为返回值¶
通过使用引用来替代指针,会使 C++ 程序更容易阅读和维护。返回指针的话可以表示指针的数组名。
int value[] = {0, 1, 2, 3};
int *GetPointerValue(int i) {
return &value[i];
}
int *GetPointersValue() {
int *r = new int[4];
for (int i = 0; i < 4; i++) {
r[i] = value[i];
}
return r;
}
int &GetQuoteValue(int i) {
return value[i];
}
int main() {
std::cout << value[0] << std::endl;
*GetPointerValue(0) = -1;
std::cout << value[0] << std::endl;
GetQuoteValue(0) = -2;
std::cout << value[0] << std::endl;
int *r = GetPointersValue();
std::cout << r[0] << " " << r[1] << " " << r[2] << std::endl;
}
-----------
0
-1
-2
-2 1 2
-----------
引用返回局部变量不合法的,下边能编译通过,而且测试运行正常,但是如果 b 所在内存给其他再次使用过,那程序就炸了。
7 实现多态¶
这俩也没啥大区别。