C++基础知识 (引用)

⭐️ 往期相关文章

✨ 链接:C++基础知识(命名空间、输入输出、函数的缺省参数、函数重载)

⭐️ 引用

引用从语法的层面上讲:引用不是定义一个新的变量,而是给已存在的变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间

例1

#include 
using namespace std;

int main() {

	int a = 10;
	int& ra = a;
	cout << ra << endl;

	ra = 20;
	cout << a << endl;

	return 0;
}

ps:  int& ra = a 这里的 raa 的引用(或者可以理解成 a 的别名),当 cout << ra 的时候相当于 cout << a ,当修改 ra = 20 的时候,a 的值也被修改了。

引用的特性:

  • 引用在定义时必须初始化
    • int& ra;   这种行为是 error
  • 一个变量可以存在多个引用
    • int num = 10;
    • int& q_num1 = num;
    • int& q_num2 = num;
  • 引用一旦引用一个实体,就不能再引用其他的实体
    • int num = 10;
    • int n = 20;
    • int q_num = num;
    • q_num = n    这里并不代表更换了引用。而是赋值:这里 q_num = n 是把 n 的值赋值给 q_numq_num 又是 num 的引用,就相当于 n 的值赋值给 num

引用的使用场景:

例2

#include 
using namespace std;

// 做参数
void swap(int& qa, int& qb) {
	int temp = qa;
	qa = qb;
	qb = temp;
}

int main() {

	int a = 10;
	int b = 20;
	cout << a << " " << b << endl;	// 10 20
	swap(a , b);
	cout << a << " " << b << endl;  // 20 10

	return 0;
}

ps: 当参数过大时,传值与传引用效率上会有一定的差距。


例3

#include 
using namespace std;

// 做返回值
int& func() {
	static int count = 0;
	cout << count << endl;
	count++;

	return count;
}

int main() {

	int res = func();
	res++;
	func();

	return 0;
}

C++基础知识 (引用)_第1张图片


ps: 首先这里 count 变量是被 static 修饰过的,所以并不是存在在栈区,而是静态区。return count 但是函数的返回是引用相当于返回了 count 的别名(这里可以理解为当函数栈帧销毁并且返回值的时候,会有一个临时变量来存储这个要返回的值,也就是可以理解成 int& temp = count 再把temp 引用返回),其实本质上就 count,所以当 count 的引用赋值给 res 就相当于把 count 赋值给 res 所以 res 的改变并不会影响静态区中的 count但是下面这种情况又不一样了。

例4

#include 
using namespace std;

int& func() {
	static int count = 0;
	cout << count << endl;
	count++;

	return count;
}

int main() {

	int& res = func();
	res++;
	func();

	return 0;
}

C++基础知识 (引用)_第2张图片


ps1: 这里返回值是被 int& res 接收的。而 res 相当于是静态区中 count 的别名,res++ 就相当于静态区中的 count++ , 所以第二次函数调用的时候 cout << count << endl 的时候是 2
ps2: 如果函数中的变量会被销毁则不可以使用引用返回,则必须使用传值返回。

例5

#include 
#include 
using namespace std;

int& At(int * nums) {
	assert(nums);

	return nums[0];
}

int main() {

	int nums[10] = { 1 , 2 };

	At(nums) = 10;	// 直接可以修改返回值

	cout << nums[0] << endl;	// 10

	return 0;
}

ps: 使用返回引用的方式是可以直接修改返回值的,但是如果使用返回值的方式是不可以直接修改的,因为返回值会创建一个临时变量来保存,这个临时变量是常值变量不可被修改。

常引用:

例6

int main () {
	const int b = 20;
	//int& qb = b;	// error
	const int& qb = b;
}

ps: b 是被 const int 修饰的常量只有读的权限 而 qbint 类型的引用,这里是 error 的因为对于引用来说权限是不可以放大的。

例7

int main () {
	
	int c = 30;
	const int& qc = c; // 这样做是可以的 权限缩小
	
	const int& d = 20; // 这样也是可以的
}

ps: 权限是可以缩小的 c 是可读可写的,而它的引用也可以是只读的。

例8

int main () {
	int e = 50;
	//double& dd = e;	// error
	const double& dd = e;
}

ps: 当把整型给到浮点型时会发生自动类型转换,但是为什么整型 e 给不了 double 的引用呢?因为在自动类型转换的时候,首先并不会改变 e 的类型,而是在它们中间创建一个临时的变量e 给到这个临时变量在通过临时变量给到 dd。而这个临时变量是一个常值变量是不可以被修改的,所以这里本质上是发生权限放大的问题,如果原变量没有被 const 修饰,或者说不是一个常量,那么它的引用可以被 const 修饰也可以不被 const 修饰(引用的权限平移或者权限缩小),但是如果原变量是一个常量或者被 const 修饰,那么它的引用只能被 const 修饰,而不可以不被const修饰(权限放大)。


引用和指针的区别

在语法概念上引用就是一个别名,没有独立的空间,和引用的实体共用同一块空间。但是在底层实现上实际是有空间的,因为引用的是按照指针方式来实现的。

引用和指针的不同点:

  • 引用概念上是定义一个变量的别名,而指针是存储一个变量的地址。
  • 引用在定义时必须初始化,指针没有要求。
  • 引用在初始化时引用一个实体后,就不能引用其他的实体,而指针可以随意的更换指向。
  • 没有 NULL 引用,但是有 NULL 指针。
  • sizeof 中的含义不同:引用结果为引用类型的大小,但是指针始终是地址空间所占的字节个数(32位平台下4字节)。
  • 引用自增 1 即引用的实体增加 1 ,指针加 1 代表的是指针的指向后偏移一个类型的大小。
  • 有多级指针,没有多级引用。
  • 访问实体的方式不同,指针需要解引用操作符,而引用编译器会自己处理。
  • 引用相比指针更安全。

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