c++之引用(五千字长文详解!)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++之引用(五千字长文详解!)相关的知识,希望对你有一定的参考价值。
c++之引用详解
#include <iostream>
using namespace std;
int main()
int a = 0;
int& b = a;//引用
a++;
printf("&a = %p,a = %d\\n", &a, a);
b++;
printf("&b = %p,b = %d\\n", &b, b);
return 0;
引用在实际当中的价值
做参数!
//可用于减少拷贝次数!
void Swap(int& left, int& right)
int temp = left;
left = right;
right = temp;
//这种就叫做输出型参数!就是说我的参数在里面进行修改,然后还要传回来!
BTNode* BinarYTreeCreat(BTDataType* a,int* pi);//此处的pi就可以使用 引用来代替!
//可以用于简化二级指针!
typedef struct ListNode
int val;
struct ListNode* next;
LTNode,*PTNode;
void SlistPushBack(LTNode** phead, int val);//这是最原始的链表插入,因为要改变头所以要引入二级指针!
void SlistPushBack(LTNode*& phead, int val);//这是对原本的基础上进行改进,使用引用代替二级指针!
void SlistPushBack(PTNode& phead, int val);//这是最后的优化版本!
做返回值
int& Count()
static int n = 0;
n++;
return n ;
//着叫做引用返回
int Count()
static int n = 0;
return n;
//这叫做传值引用
传值返回
讲n的数据拷贝到临时变量
最后临时变量拷贝到变量a
为了直观理解我将count的栈帧画在了main的上方,从物理上面看,main的栈帧是在上面的,因为栈帧是向下生长的!
引用返回
直接从n将数据拷贝到变量a
对比传值返回和引用返回的效率
以值作为参数或者返回值类型,在传参和返回期间,函数不会==直接传递实参或者将变量本身直接返回==,而是传递实参或者返回变量的==一份临时的拷贝==,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是==当参数或者返回值类型非常大时,效率就更低!==
#include <time.h>
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();
关于static在引用中的作用!
int& Count()
static int n = 0;
n++;
return n ;
在这种状态下进行访问,我们可能会得到我们想要的数据,也可能能得不到我们想要的数据,都有可能!
关于引用返回的结论
关于临时向量
引用返回的意义
关于引用和重载
#include <iostream>
using namespace std;
void swap(int& a,int& b)
int temp = a;
a = b;
b = temp;
void swap(int a,int b)
int temp = a;
a = b;
b = temp;
int maim()
int a =1;
int b = 1;
swap(a,b); //程序会报错!因为虽然可以构成重载!但是编译器不知道应该调用那个函数!
return 0;
常引用
int a = 10;
这个变量a的类型为int ,它的权限能读能写,我们既可以访问,也可以修改
const int a = 10;
这个变量的类型为 const int ,它的权限只能读不能写,我们只能对它进行访问,但是不能对该变量进行修改!
权限的赋予
当我们将一个引用进行初始化的时候就是将权限进行了一次赋予
int a = 10;
int& test = a;
==这时候 变量test和变量a对于同一块内存空间都有着相同的权限!==因为两者同为int类型!
int a = 10;
const int& test = a;
将int类型的变量,对常引用进行初始化,这就是典型的权限缩小
因为常引用初始化后就可以当成一般变量进行使用,但是const 前缀的变量不可以对内存数据进行修改,而原本的变量仍然可以,这就是权限缩小!
const int a = 10;
int& test = a;
**这就是权限放大!原本的变量为const int类型,初始化后只能对该变量进行访问但是不能修改!我们使用该变量对int&类型的引用进行初始化!就会发生权限放大!因为int类型的变量是被允许对内存进行修改和读取的!**这是不被允许的!会导致编译报错!
int a = 10;
const int& b = a;
b++;//报错!
a++;//可执行!
b++会报错是因为变量b的权限仅仅只有读,不能写!但是a的变量权限可读可写,所以a++这行代码是可执行的!虽然它们同属一块内存空间,但是权限的不同!而且变量b的权限虽然缩小,但是变量a的权限仍然是不变的!
常引用的实际价值
常引用与临时变量
double a = 1.00;
int& b = (int*)a;
当我们第一次看到这个代码的时候,我们可能会觉得这没有问题啊?double强制转成int然后作为目标变量名将b初始化。
但是这个是个错误的代码!因为我们上文说过强制类型转换必产生==临时变量==,而临时变量具有==常性!==也就是说类型是const开头的!这就犯了权限放大的错误!
正确的代码应该是
double a = 1.00;
const int& b = (int*)a;
//下面这样也行
//const int&b = a;
//因为发生了隐形的强制类型转换!上面的是显性的强制类型转换!
//但是无论是隐形还是显性都会产生临时变量!
为了避免忘记,也请记住上文提到过的传值返回的是临时变量!具有常性!
int Count()
int n = 0;
n++;
return n;
int main()
int& a = Count();//显然这也是错误的!返回值的实际真正类型为const int!
return 0;
正确的代码为
int Count()
int n = 0;
n++;
return n;
int main()
const int& a = Count();
return 0;
常引用的常量初始化
我们已知引用必须初始化!但是是否能使用常量对于引用进行初始化呢?
int& a = 1;
上面的代码是错误的!为什么?
因为在c++中常量的类型为const int!还是老样子犯了权限放大的错误!所以解决办法也是一样的!
const int& a = 1;//这样就可以对使用常量对a进行初始化了!
常引用与缺省参数
void func(int& N = 10)
//...
由上面的结论我相信,读者们也可以看出了吧,我们已知缺省参数一定要是全局变量或者常数,当我们缺省值使用常数的时候,类型为 const int,该代码又发生了权限放大!所以还是一样的修改!
void func(const int& N = 10)
//...
结论
引用和指针的不同点
- 引用概念上定义一个变量的别名,指针存储一个变量地址。
- . 引用在定义时必须初始化,指针没有要求
- 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何 一个同类型实体
- 没有NULL引用,但有NULL指针(就是说引用不可以使用NULL进行初始化!)
- 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32 位平台下占4个字节)
- 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
- 有多级指针,但是没有多级引用
- 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
- 引用比指针使用起来相对更安全
常引用的使用注意
- 注意权限的放大和缩小
- 注意强制类型转换,传值返回产生了临时变量!
- 注意常数的类型!
一点补充
在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
int main()
int a = 10;
int& ra = a;
cout << "&a = " << &a <<endl;
cout << "&ra = " << &ra <<endl;
但是在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。
int main()
int a = 10;
int& ra = a;
ra = 20;
return 0;
int main()
int a = 10;
int* pa = a;
*pa = 20;
return 0;
以上是关于c++之引用(五千字长文详解!)的主要内容,如果未能解决你的问题,请参考以下文章
c++之类和对象——类的定义,存储方式,this指针!(五千字长文详解!)