0
点赞
收藏
分享

微信扫一扫

C++ Lesson 2.引用

q松_松q 2022-04-17 阅读 30
c++

C++ Lesson 2.引用

C++ Lesson 2.引用

1. 引用

a. 引用概念

引用不是新定义一个变量,而是给已存在的变量取一个别名,当然可以取多个别名,编译器也不会为引用变量开辟内存空间,引用实体和它引用的变量共用同一块内存空间

int main()
{
	//注:引用类型必须与引用实体为同种类型
	int a = 123;
	int& ra = a;//类型 &引用变量名(对象名)=引用实体
	cout << a << " " << ra << endl;
	cout << &ra << " " << &a << endl;
	return  0;
}
123 123
000000E06196FC44 000000E06196FC44

b. 引用特性

i. 引用在定义是必须初始化
ii. 一个变量可以有多个引用
iii. 引用一旦引用一个实体,再也不能引用其他实体

c. 常引用

//常引用
int main() 
{
	double d = 12.34;
	//int& rdd = d;引用类型必须与引用实体为同种类型
	const int& rd = d;//why?
	cout << d <<endl<< rd << endl;
}
12.34
12

const int& rd=d;拿到整形部分,发生隐式转换
在编辑器中会创建一个临时变量(不知道变量名,不知道地址,具有常性),将隐式转换后的值放入rd中。临时变量具有常性,所以 const int& rd = d;

d. 使用场景

i.概念:给引用实体取别名——简化代码

struct A
{
	int a = 10;
	struct B
	{
		int b = 20;
	};
	struct B bb;
};

int main()
{
	struct A aa;
	int& ra = aa.a;
	int& rb = aa.bb.b;
	cout << ra << " " << rb << endl;
}
10 20

ii.做参数
如果引用类型作为函数形参,尽量传递引用
如果不想通过形参修改外部实参,将引用给为const int&

void swap( int& left,  int& right)//会修改外部实参
{
	int temp = left;
	left = right;
	right = temp;
}
int main()
{
	int a = 123;
	int b = 456;
	int& ra = a;
	int& rb = b;
	cout << a << " " << b << endl;
	swap(ra,rb);
	cout << a << " " << b << endl;
	return 0;
}
123 456
456 123

iii.做返回值

//3.作为函数的返回值类型
using namespace std;
int& Add(int left, int right)
{
	int temp = left + right;
	cout << &temp << endl;
	return temp;
}
//当Add函数运行完毕后,函数的栈帧已经被系统收回,
//及Add对应的栈帧空间不能使用了,但是空间还在,
//而且Add运行完成之后在空间中留下的垃圾数据并没有被消除


//注:如果引用方式作为函数返回值类型,不能返回函数栈上的空间
//如果返回,则返回的实体必须比函数的生命周期要长
int main()
{
	int& ret = Add(10, 20);
	cout << ret << endl;
	Add(20, 30);
	cout << ret << endl;
	Add(40,50);
	cout << ret << endl;
	return 0;
}
000000E77F7BFA64
30
000000E77F7BFA64
50
000000E77F7BFA64
90

注意:如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已经还给系统了,则使用传值返回或使用const 类型& 引用变量名(对象名)

e. 传值传址传引用效率比较

传址,引用效率几乎相同并且更好,传值效率非常低下

#include <time.h>
struct A { int a[10000]; };
void TestFunc1(A a) {}
void TestFunc2(A* a) {}
void TestFunc3(A& a) {}
void TestRefAndValue(int num)
{
	A a;
	// 以值作为函数参数
	size_t begin1 = clock();
	for (size_t i = 0; i < num; ++i)
		TestFunc1(a);
	size_t end1 = clock();
	// 以指针作为函数参数
	size_t begin2 = clock();
	for (size_t i = 0; i < num; ++i)
		TestFunc2(&a);
	size_t end2 = clock();
	// 以引用作为函数参数
	size_t begin3 = clock();
	for (size_t i = 0; i < num; ++i)
		TestFunc3(a);
	size_t end3 = clock();
	// 分别计算三个函数运行结束后的时间
	cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
	cout << "TestFunc2(A*)-time:" << end2 - begin2 << endl;
	cout << "TestFunc3(A&)-time:" << end3 - begin3 << endl;
}
int main()
{
	int num=10000000;
	TestRefAndValue(num);
	return 0;
}
TestFunc1(A)-time:8998
TestFunc2(A*)-time:32
TestFunc3(A&)-time:40

f. 值,指针,引用作为返回值类型的性能比较

值作为返回值类型的性能很差,指针和引用作为返回值类型的性能更好

#include <time.h>
using namespace std;
struct A { int a[10000]; };
A a;
// 值返回
A TestFunc1() { return a; }
// 引用返回
A& TestFunc2() { return a; }
// 指针返回
A* TestFunc3() { return &a; }
void TestReturnByRefOrValue(int num )
{
	// 以值作为函数的返回值类型
	size_t begin1 = clock();
	for (size_t i = 0; i < num; ++i)
		TestFunc1();
	size_t end1 = clock();
	// 以引用作为函数的返回值类型
	size_t begin2 = clock();
	for (size_t i = 0; i < num; ++i)
		TestFunc2();
	size_t end2 = clock();

	// 以指针作为函数的返回值类型
	size_t begin3 = clock();
	for (size_t i = 0; i < num; ++i)
		TestFunc3();
	size_t end3 = clock();
	// 计算三个函数运算完成之后的时间
	cout << "TestFunc1 time:" << end1 - begin1 << endl;
	cout << "TestFunc2 time:" << end2 - begin2 << endl;
	cout << "TestFunc3 time:" << end3 - begin3 << endl;
}
int main()
{
	int num = 10000000;
	TestReturnByRefOrValue(num);
	return 0;
}
TestFunc1 time:17662
TestFunc2 time:34
TestFunc3 time:40

g. 引用与指针的区别

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

引用和指针不同点

1.引用在定义时必须初始化,指针没有要求(指向一个合法的内存空间或指向NULL;更合理)
2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体

int a=10;
int& ra=a;
//int* const ra=a;(指向不可被修改)
  1. 没有NULL引用,但有NULL指针
  2. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占
    4个字节)
  3. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
const int&& rra = 10;
//注:T&&是C++11中的新特性,称为右值引用

6.有多级指针,但是没有多级引用
7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
8. 引用比指针使用起来相对更安全

举报

相关推荐

0 条评论