上期回顾
一、引用的诞生
二、引用的概念
我们了解了概念之后,那引用是如何使用的呢?
三、引用的使用
#include <iostream>
using namespace std;
int main()
{
int a = 3;
int&a1 = a;
cout << "a = "<< a << endl << "a1 = "<< a1 << endl;
return 0;
}
四、引用的特性
4.1 引用必须初始化
#include <iostream>
using namespace std;
int main()
{
int a = 3;
int&a1;
return 0;
}
4.2 引用的改变 会 改变引用实体
#include <iostream>
using namespace std;
int main()
{
int a = 3;
int&a1 = a;
a1++;
cout << "a = "<< a << endl << "a1 = "<< a1 << endl;
return 0;
}
4.3 引用不改变指向,也不可以同时引用多个实体
#include <iostream>
using namespace std;
int main()
{
int a = 3;
int&a1 = a;
int b = 5;
a1 = b;
cout << "a = "<< a << endl << "a1 = "<< a1 << endl;
cout << "a的地址为:"<< &a << endl;
cout << "a1的地址为:"<< &a1 << endl;
cout << "b的地址为:"<< &b << endl;
return 0;
}
4.4 一个实体可以有多个引用
#include <iostream>
using namespace std;
int main()
{
int a = 3;
int& a1 = a;
int& a2 = a;
int& a3 = a;
cout << "a = "<< a << endl;
cout << "a1 = "<< a1 << endl;
cout << "a2 = "<< a2 << endl;
cout << "a3 = "<< a3 << endl;
return 0;
}
我们可以发现,目前的引用都是在引用变量,那是否可以引用常量或者是常变量呢?接下来是我们要讲的重点之一:
五、常引用
在学习之前,我们要先知道这个概念
那什么是常引用呢?就是对常量和常变量的引用,但是一定要记住权限,来看下面的代码:
#include <iostream>
using namespace std;
int main()
{
const int a = 3;
int& a1 = a;
return 0;
}
那怎么弄才是对的呢?还是得看权限只能平移和缩小,所以我们更改了代码:
#include <iostream>
using namespace std;
int main()
{
const int a = 3;
const int& a1 = a;
return 0;
}
那有没有权限缩小的呢?当然有,来看下面代码:
#include <iostream>
using namespace std;
int main()
{
int a = 3;
const int& a1 = a;
return 0;
}
以上都是对常变量的引用,那如何来引用常量呢?
#include <iostream>
using namespace std;
int main()
{
const int &a1 = 3;
return 0;
}
六、引用和引用实体的数据类型不同
我们要了解一个概念,当类型不同的时候,一定会发生类型转换,比如下面的代码:
#include <stdio.h>
int main()
{
int a = 3;
double b = a;
printf("a = %d\nb = %lf",a,b);
return 0;
}
我们先定义了一个整形变量a,再将a变量赋值给double类型的b,两个类型不同,会发生隐式类型转换,就是把a转换成double类型,再赋值给b,那我们的a的数据类型是什么呢?
从上面可以看出a还是整型,但是不是把a转换成double之后,再赋值给b的吗?怎么a还是int类型?我们带着这样的疑问,去学习一个新的知识:
凡是涉及到类型的转换,都会产生一个临时变量,存放转换的值。这个临时变量具有常属性
这也就解释了为什么a还是int类型。
我们用图解的方法来看一下:
我们在了解上面的概念之后,看下面的代码:
#include <iostream>
using namespace std;
int main()
{
int a = 3;
const double& b = a;
return 0;
}
七、引用的使用场景
其实在上面我们仅仅是在介绍引用该怎么使用,没有介绍引用都用在哪里,所以接下来我们来学习引用使用场景。
7.1 做函数参数
void Swap(int* x,int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
而在C++中,我们可以用引用来解决这个问题:
void Swap(int& x,int& y)
{
int tmp = x;
x = y;
y = tmp;
}
7.2 做返回值
下面的例子主要是讲解,我们用引用做返回值的时候,返回值不可以被销毁。
我们先看这样的一段代码:
int& Count()
{
int n = 0;
n++;
// ...
return n;
}
using namespace std;
int main()
{
int& ret = Count();
cout << ret << endl;
return 0;
}
如果我们是下面的代码呢?打印出来的结果又是什么呢?
int& Add(int x,int y)
{
int z = x + y;
return z;
}
using namespace std;
int main()
{
int& ret = Add(1,2);
cout << ret << endl;
Add(3,7);
cout << ret << endl;
return 0;
}
但是有没有什么办法来解决这样的问题呢?也就是保证返回值不被销毁。
int& Add(int x,int y)
{
static int z = x + y;
return z;
}
using namespace std;
int main()
{
int& ret = Add(1,2);
cout << ret << endl;
return 0;
}
所以我们的我们函数返回值要是引用的话,返回值不呢被销毁
八、传值和传引用的效率比较
8.1 函数参数 用 引用和值 的效率比较
#include <time.h>
#include <iostream>
using namespace std;
struct A
{
int a[10000];
};
void TestFunc1(A a)
{
}
void TestFunc2(A& a)
{
}
void TestRefAndValue()
{
A a;
// 以值作为函数参数
size_t begin1 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc1(a);
size_t end1 = clock();
// 以引用作为函数参数
size_t begin2 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc2(a);
size_t end2 = clock();
// 分别计算两个函数运行结束后的时间
cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}
int main()
{
TestRefAndValue();
return 0;
}
8.1 函数返回值用引用和值的效率比较
#include <iostream>
#include <time.h>
using namespace std;
struct A
{
int a[10000];
};
A a;
// 值返回
A TestFunc1()
{
return a;
}
// 引用返回
A& TestFunc2()
{
return a;
}
void TestReturnByRefOrValue()
{
// 以值作为函数的返回值类型
size_t begin1 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc1();
size_t end1 = clock();
// 以引用作为函数的返回值类型
size_t begin2 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc2();
size_t end2 = clock();
// 计算两个函数运算完成之后的时间
cout << "TestFunc1 time:" << end1 - begin1 << endl;
cout << "TestFunc2 time:" << end2 - begin2 << endl;
}
int main()
{
TestReturnByRefOrValue();
return 0;
}
通过上述代码的比较,发现传值和指针在作为传参以及返回值类型上效率相差很大。这就是引用的优势,不需要开辟临时空间。