目录
引用
引用的概念和定义
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
类型& 引用别名=引用对象;
#include<iostream>
using namespace std;
int main()
{
int a = 30;
//一个变量可以取多个别名
int& b = a;//给a变量取别名
int& c = a;//c也是a的别名
int& d = b;//给b变量取别名,相当于d也是a的别名
cout << &a << endl << &b << endl << &c << endl << &d << endl;
//从地址中也可以看出来a,b,c,d占用同一块内存空间
return 0;
}
引用的特性
引用在定义时必须初始化
一个变量可以有多个引用
引用一旦引用一个实体,再不能引用其它实体
#include<iostream>
using namespace std;
int main()
{
int a = 30;
int d = 10;
//int& ra;
//报错:引用必须初始化
int& b = a;
int& c = a;//一个变量可以有多个引用
//C++中规定引用不能改变指向,所以这里不是让b引用d,而是赋值
b = d;
cout << a << " " << b;
//从打印出来的结果看,确实是赋值。改变引用对象从而改变被引用对象
return 0;
}
引用的使用
引用在实践中主要是用于引用传参和引用做返回值,可以减少拷贝提升效率和改变引用对象同时改变被引用对象。
引用传参和指针传参的功能是类似的,引用传参相对更方便一点。
#include<iostream>
using namespace std;
//传址调用,指针
void swap(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
//引用
void swap(int& a, int& b)//函数重载
{
int tmp = a;
a = b;
b = tmp;
}
int main()
{
int a = 10;
int b = 20;
swap(a, b);
swap(a, b);
return 0;
}
最终结果:
而且可以看出,引用比指针的可读性更高。
引用和指针相辅相成,功能有重叠性,但是各有特点,互相不可替代。
C++中的引用不能改变指向,JAVA的引用可以改变指向。
注意:引用传值,指针传地址。这句话是不对的。
因为在c++中引用的本质就是传地址。这是因为引用在底层实现上是通过指针来实现的。在编译器内部,引用通常会被处理为指针。
#include<iostream>
using namespace std;
int main()
{
/*int a = 10;
int& b = a;
b=10;*/
//在编译器中可能会转化为类似的操作
int a = 10;
int* b = &a;
*b = 10;
}
const引用
跟指针中const修饰类似 ,const修饰的变量具有常属性,即不能改变的属性。
访问权限可以缩小,但是不能放大。(访问权限只针对引用和指针)
#include<iostream>
using namespace std;
int main()
{
const int a = 10;//只可读
//int& b = a;
// //发生错误,b可读可写,权限变大
//应加上const
const int& b = a;
int c = 20;
const int& d = c;//权限缩小,可以
c++;
//d++;c可以改变,d不可以
return 0;
}
需要注意的是:C++规定临时对象具有常性,不能改变,所以必须要用const引用。
临时对象就是编译器需要一个空间暂存表达式的求值结果临时创建的一个未命名的对象 。
表达式运算(如:a+b,a*3),函数传值返回,类型转换(在类型转换中会产生临时对象储存中间值)都会出现临时变量
using namespace std;
int add(int a, int b)
{
return a + b;
}
int main()
{
int a = 10;
const int& b = a * 3;
const double& c = a;
const int& d = add(10, 20);
return 0;
}
引用和指针的关系
- 引用是一个变量的别名,不开空间。指针储存一个变量的地址,要开空间。
- 引用在定义时必须初始化,指针建议,但是不是必须。
- 引用在初始化引用一个对象后就不能改变指向,而指针可以不断改变。
- 引用可以直接访问指向对象,而指针必须要解引用。
- 指针很容易出现空指针和野指针的问题,而引用相对安全得多。
inline
用inline修饰的函数叫做内联函数,编译时会在调用的地方直接展开,这样就不需要建立栈帧了,可以提高效率。
inline适用于频繁调用的短小函数,它对编译器只是一个建议,你加了也不一定会直接展开。
我们可以通过汇编来观察程序是否展开,如果有call add语句就是未展开。
inline 不建议声明和定义分离到两个文件,分离会导致链接错误。这是为什么呢?
这就要提到c语言中的编译和链接了:
当声明和定义分离时,内联函数直接被展开,函数无地址,不会放入符号表,就无法被调用
分离:
//f.h
#include<iostream>
using namespace std;
inline int add(int a, int b);
//f.cpp
#include"f.h"
int add(int a, int b)
{
return a + b;
}
//main.cpp
#include"f.h"
int main()
{
add(10, 20);
return 0;
}
//报错,无法解析的外部指令
不分:
//f.h
#include<iostream>
using namespace std;
inline int add(int a, int b)
{
return a + b;
}
//main.cpp
#include"f.h"
int main()
{
add(10, 20);
return 0;
}