文章目录
- 前言
- 一、引用
-
- [1.1 引用的概念和定义](#1.1 引用的概念和定义)
- [1.2 引用的特性](#1.2 引用的特性)
- [1.3 引用的使用](#1.3 引用的使用)
- [1.4 const 引用](#1.4 const 引用)
- [1.5 指针和引用的关系](#1.5 指针和引用的关系)
- 总结
前言
上一篇学习了c++入门的一些基础部分语法,今天还有基础中最重要的一部分------引用
对的,没错,今天只有一个内容就是------引用。
引用之后就正式开始类和对象啦
一、引用
1.1 引用的概念和定义
引用不是新定义一个变量 ,而是给已存在变量取了一个别名 ,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。比如:水浒传中李逵,宋江叫"铁牛",江湖上人称"黑旋风";林冲,外号豹子头;
类型& 引用别名 = 引用对象;
C++中为了避免引入太多的运算符 ,会复用C语言的一些符号 ,比如前面在输入和输出的部分 << 和 >> ,这里引用也和取地址使用了同一个符号&,容易混淆,注意区分。
代码更好理解,就是给原来的变量取了一个外号
cpp
#include<iostream>
using namespace std;
int main()
{
int a = 0;
// 引用:b和c是a的别名
int& b = a;
int& c = a;
// 也可以给别名b取别名,d相当于还是a的别名
int& d = b;
++d;
// 这里取地址我们看到是一样的
cout << &a << endl;
cout << &b << endl;
cout << &c << endl;
cout << &d << endl;
return 0;
}
1.2 引用的特性
• 引用在定义时必须初始化
• 一个变量可以有多个引用
• 引用一旦引用一个实体,再不能引用其他实体
cpp
#include<iostream>
using namespace std;
int main()
{
int a = 10;
// 编译报错:"ra": 必须初始化引用
//int& ra;
int& b = a;
int c = 20;
// 这里并非让b引用c,因为C++引用不能改变指向,
// 这里是一个赋值
b = c;
cout << &a << endl;
cout << &b << endl;
cout << &c << endl;
return 0;
}
1.3 引用的使用
• 引用在实践中主要是用于:引用传参和引用做返回值中减少拷贝提高效率和改变引用对象时同时改变被引用对象。
• 引用传参跟指针传参功能是类似的,引用传参相对更方便一些 。
• 引用返回值的场景相对比较复杂 ,我们在这里简单讲了一下场景。
• 引用和指针在实践中相辅相成,功能有重叠性 ,但是各有特点,互相不可替代。C++的引用跟其他语言的引用(如Java)是有很大的区别的,除了用法,最大的点,C++引用定义后不能改变指向 ,Java的引用可以改变指向。
cpp
void Swap(int& rx, int& ry)
{
int tmp = rx;
rx = ry;
ry = tmp;
}
int main()
{
int x = 0, y = 1;
cout << x <<" " << y << endl;
Swap(x, y);
cout << x << " " << y << endl;
return 0;
}
这里的swap函数就不用像以前那样传指针写,直接传引用,改变的是实参
再来看看以前学过的数据结构的代码,把指针改成引用
cpp
#include<iostream>
using namespace std;
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
void STInit(ST& rs, int n = 4)
{
rs.a = (STDataType*)malloc(n * sizeof(STDataType));
rs.top = 0;
rs.capacity = n;
}
// 栈顶
void STPush(ST& rs, STDataType x)
{
assert(ps);
// 满了, 扩容
if (rs.top == rs.capacity)
{
printf("扩容\n");
int newcapacity = rs.capacity == 0 ? 4 : rs.capacity * 2;
STDataType* tmp = (STDataType*)realloc(rs.a, newcapacity *
sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
return;
}
rs.a = tmp;
rs.capacity = newcapacity;
}
rs.a[rs.top] = x;
rs.top++;
}
// int STTop(ST& rs)
int& STTop(ST& rs) // 这里用了引用做返回 正常返回值时形参是拷贝的内容 不能对原本的内容进行修改
{ // 但是传引用的话,传的是参数的别名,能直接修改实参
assert(rs.top > 0);
return rs.a[rs.top];
}
int main()
{
// 调用全局的
ST st1;
STInit(st1);
STPush(st1, 1);
STPush(st1, 2);
cout << STTop(st1) << endl;
STTop(st1) += 10;
cout << STTop(st1) << endl;
return 0;
}
cpp
#include<iostream>
using namespace std;
typedef struct SeqList
{
int a[10];
int size;
}SLT;
void SeqPushBack(SLT& sl, int x)
{}
typedef struct ListNode
{
int val;
struct ListNode* next;
}LTNode, *PNode;
// 指针变量也可以取别名,这里LTNode*& phead就是给指针变量取别名
// 这样就不需要用二级指针了,相对而言简化了程序
//void ListPushBack(LTNode** phead, int x)
//void ListPushBack(LTNode*& phead, int x)
void ListPushBack(PNode& phead, int x)
{
PNode newnode = (PNode)malloc(sizeof(LTNode));
newnode->val = x;
newnode->next = NULL;
if (phead == NULL)
{
phead = newnode;
}
else
{
//...
}
}
int main()
{
PNode plist = NULL;
ListPushBack(plist, 1);
return 0;
}
可以看到,传引用还是相对于传指针要方便很多
在类和对象的学习中,引用可就是必不可少的一部分,不然小编也不会整整一篇文章围绕引用
1.4 const 引用
• 可以引用一个const对象,但是必须用const引用。const引用也可以引用普通对象,因为对象的访问权限在引用过程中可以缩小,但是不能放大。
• 不过需要注意的是类似int& rb = a3; double d = 12.34; int& rd = d; 这样一些场景下a 3的和结果保存在一个临时对象中, int& rd = d 也是类似,在类型转换中会产生临时对象存储中间值,也就是说rb和rd引用的都是临时对象,而C++规定临时对象具有常性,所以这里就触发了权限放大,必须要用常引用才可以。
• 所谓临时对象就是编译器需要一个空间暂存表达式的求值结果时临时创建的一个未命名的对象,C++中把这个未命名对象叫做临时对象。
看看代码更好理解
cpp
#include<iostream>
using namespace std;
int main()
{
int a = 10;
const int& ra = 30;
// 编译报错: "初始化": 无法从"int"转换为"int &"
// int& rb = a * 3;
const int& rb = a*3;
double d = 12.34;
// 编译报错:"初始化": 无法从"double"转换为"int &"
// int& rd = d;
const int& rd = d;
return 0;
}
cpp
int main()
{
const int a = 10;
// 编译报错: "初始化": 无法从"const int"转换为"int &"
// 这里的引用是对a访问权限的放大
//int& ra = a;
// 这样才可以
const int& ra = a;
// 编译报错: "ra": 不能给常量赋值
//ra++;
// 这里的引用是对b访问权限的缩小
int b = 20;
const int& rb = b;
// 编译报错:error C3892: "rb": 不能给常量赋值
//rb++;
return 0;
}
1.5 指针和引用的关系
C++中指针和引用就像两个性格迥异的亲兄弟,指针是哥哥,引用是弟弟,在实践中他们相辅相成,功能有重叠性,但是各有自己的特点,互相不可替代。
• 语法概念上引用是一个变量的取别名不开空间 ,指针是存储一个变量地址,要开空间。
• 引用在定义时必须初始化 ,指针建议初始化,但是语法上不是必须的 。
• 引用在初始化时引用一个对象后 ,就不能再引用其他对象 ;而指针可以在不断地改变指向对象 。
• 引用可以直接访问指向对象 ,指针需要解引用才是访问指向对象 。
• sizeof中含义不同**,引用结果为引用类型的大小**,但指针始终是地址空间所占字节个数 (32位平台下占4个字节,64位下是8byte)
• 指针很容易出现空指针和野指针的问题,引用很少出现,引用使用起来相对更安全一些。
总结
从引用的概念和定义到使用再到const引用,最后的引用与指针的区别
深刻理解到引用和指针的差别,引用的用处还是很多的
再后序的类和对象学习当中会经常用到,不要走开,小编持续更新中~~~~