C++拾遗(四)引用与指针

引用和指针是两种不同的概念,尽管它们在某些方面有一些相似之处,但它们在功能和用途上是有所区别

声明与定义

引用:引用是别名,是对已存在变量的另一个称呼,一旦一个变量被引用,就不能再被引用其他变

量。

int a = 10;

int& ref = a; 

这里,ref 是 a 的引用,它们引用的是同一个对象。

指针:指针是一个变量,其值为另一个变量的地址。指针可以被重新赋值以指向其他变量。

int a = 10;

int* ptr = &a; 

这里,ptr 是一个指向 a 的指针。

初始化和绑定

引用:引用必须在声明时就初始化,并且一旦一个引用被绑定到一个对象,就不能再被重新绑定到其他对象。

指针:指针可以在任何时候被初始化,也可以被重新指向其他对象。

int a = 10;

int* ptr = &a; 

int b = 20;

ptr = &b; 

这里,指针 ptr 被重新指向了 b

间接性

引用:引用不具有间接性,一旦一个变量被引用,就可以像使用该变量一样直接使用这个引用。

int a = 10;

int& ref = a;

std::cout << ref << std::endl;  

这里可以直接使用 ref,不需要间接性。

指针:指针具有间接性,必须通过解引用来使用指针所指向的对象。

int a = 10;

int* ptr = &a;

std::cout << *ptr << std::endl; 

这里需要使用 *ptr 来获取指针所指向的值。

操作

引用:引用本身不进行任何操作,对引用的操作实际上是对所引用的对象的操作。

int a = 10;

int& ref = a;

ref = 20; 

这里对引用的操作实际上是对所引用的对象的操作,此时a为20

指针:指针可以进行各种操作,如指针算术、比较等。

int a = 10;

int* ptr = &a;

*ptr = 20; 

这里对指针的操作会影响指针所指向的值,此时a为20

空值

引用:引用不能为空。

指针:指针可以为空。

int* ptr = nullptr;

动态内存分配

引用:不能用于动态内存分配。

指针:可以用于动态内存分配,如new

int* ptr = new int(20);

使用场景

引用:在函数参数传递、函数返回值等场景中经常使用引用,以提高效率并避免不必要的拷贝。

指针:在动态内存分配、实现复杂的数据结构(如链表、树等)时经常使用指针。

安全性

引用:使用引用更安全,因为它们不能被重新指向其他对象,也不能为空。

指针:指针可以指向无效的内存地址或未初始化的内存,因此使用指针需要更多的注意和小心。

取地址操作

引用:不能取一个引用的地址。

指针:可以取一个变量的地址,得到一个指向该变量的指针。

别名问题

引用:如果一个引用和它所引用的变量在程序的其他地方被改变,那么这个引用将会反映这些改

变。也就是说,引用是它所引用的变量的别名。

指针:一个指针可以被改变以指向另一个变量,但并不会影响原始变量的地址。也就是说,指针并

不一定是它所指向变量的别名。

引用使用场景

1.当需要将一个对象的引用分配给另一个变量时,应使用引用。

2.在函数参数中,期望的是按引用传递并修改原始数据,应使用引用。

3.在初始化列表中(如构造函数初始化列表),应该使用引用来初始化其他引用类型的变量。

指针使用场景

1.当从函数返回一个大的数据结构时,通常使用指针或智能指针。因为返回一个大的数据结构按值

传递会非常低效。

2.指针可以在任何时候指向任何对象。

3.指针可以指向一个空值。

4.对于动态分配的内存,应使用智能指针(如 std::unique_ptr 或 std::shared_ptr)而不是原始指针。

5.当重载操作符(如 operator->)时,通常会使用指针而不是引用,因为这些操作符期望的是一个指针类型的参数。

6.当模板参数是类类型时,因为类类型可能没有默认构造函数,而引用必须能够被初始化为一个有

效的对象。在这种情况下,使用指针作为模板参数可以避免编译错误。

7.将一个基类的指针转换为派生类的指针。这通常是通过多态来实现的。在这种情况下,应该使用

指向基类的指针,并在需要时进行类型转换。

8.在回调函数和函数指针的上下文中,通常使用原始指针而不是引用,因为回调函数通常以按值传

递的方式工作。此外,函数指针本身就是一个指向函数的指针,而不是对象的引用。

9.当需要传递大型数据结构或对象时,通过指针传递通常比按值传递更高效。

你可能感兴趣的:(c++,开发语言)