从C++开始的编程生活(3)——引用类型、内联inline和nullptr

发布于:2025-07-22 ⋅ 阅读:(12) ⋅ 点赞:(0)

前言

本系列文章承接C语言的学习,需要有C语言的基础才能学会哦~
第3篇主要讲的是有关于C++的引用类型内联inlinenullptr
C++才起步,都很简单呢!

目录

前言

引用类型

基本语法

特性

应用

const引用

基本语法

引用与指针的关系

内联inline

nullptr


引用类型

即对同一块连续存储空间,多取一个标识符(别名)语法上不开辟空间(但是汇编底层也是用指针实现的)

基本语法

int a = 0;
int& b = a;

如上,引用类型的定义方式为:类型& 引用别名 = 引用对象(“类型”,要与引用对象相同)。
这里表示引用b为a的别名
引用类型变量同原变量指向同一空间,即a,b都指向同一块空间。

int a = 0;
int& b = a;
int& c = a;
//也可以给别名取别名
int& d = c;
//运行代码,四次输出的地址都相同,可知引用类型与原变量a指向同一个地址
cout << &a << endl;
cout << &b << endl;
cout << &c << endl;
cout << &d << endl;

而且,可以给别名起别名(如上代码)。
一个变量可以有多个别名

特性

①引用在定义时必须初始化
②一个变量可以有多个别名。
③引用不可以再改变指向。

应用

引用传参和引用做返回值的时候减少拷贝,从而提高效率。而且改变引用类型对象同时会改变被引用对象

struct A
{
	int arr[1000];//占用空间大
};
//不使用引用传参和指针传参
int Func(A aa)
{
	//此处需要拷贝一个占用较大的A类型,效率低
	return aa.arr[0];
}
int& Func2(A& aa)
{
	//此处返回值和传参都无需拷贝
	return aa.arr[0];//数组首元素
}
//并且,若修改返回的值,数组的首元素同时也会被修改。
int main()
{

	struct A aa;
	for (int i = 0; i < 1000; i++)
	{
		aa.arr[i] = i;
	}
    //首元素为0,输出为1
	cout << ++Func2(aa) << endl;

	return 0;
}

首先,将返回值传回时,还会开辟一个临时对象存储返回值。这里使用了引用作返回值。
然后,将引用类型作为临时对象返回,无需再进行拷贝无需开辟空间,因为引用是被引用对象的别名,可以认为是同一个变量。
而且可以通过修改返回值,达到修改被引用对象的作用
调用Func2,可以Func2(aa)++,改变返回值,即可修改原数组的首元素
调用Func,Func(aa)++会报错,因为返回的是个int类型数据,他不是一个左操作数。


注意,不可以出现野引用现象(类似野指针)!!

const引用

const引用,用于引用const对象,也可以引用普通对象。(const对象,不可被赋值,必须初始化)

基本语法

const int a = 0;
const int& b = a;

引用const对象,要使用const引用。否则·······

这是一个关于访问权限的问题(指针和引用才有)。

访问权限演示
//①
const int a = 0;
//!!错误演示!!
int &b = a;//int&引用指向的对象是可以修改的,这里放大了访问权限
//!!正确演示!!
const int& ra = a;

//②
int c = 10;
const int&rc = c;//该引用为访问权限为const,缩小了权限,是允许的
//因此↓
c++;//c可以被修改
rc++;//不可以通过rc修改c

//③
double d = 12.34;
const int& rd = d;//d先要进行类型转换转为int,中间产生临时const对象,传给rd时要求rd也是const引用
void func(const int& rx)
{
    int ret = rx;
    return ret;
}
int e = 10;
const int& re = e * 10;//e * 10的中间结果为临时const对象,同上处理
func(e);//e的权限缩小为const
func(e * 3);//e * 3为临时const对象,函数传参要为const引用
//综上,类型转换、中间值、传参等情况可能会出现访问权限的问题

 C++在类型转换或者多次运算时,中间结果也为const对象

引用与指针的关系

①指针和引用相辅相成,各有特点,不可替代
②在语法上,引用不开辟空间存储指针变量要开辟空间存储
引用必须初始化指针可以不初始化(只是建议要初始化)。
引用可以直接访问对象指针还需要解引用
在sizeof中,表达含义不同,引用,则为所引用的类型的大小指针,则是指向地址空间的字节个数
指针容易出现空指针和野指针引用很少会出现野引用,引用使用起来更安全。
⑦因为引用在初始化之后就不可以再赋值,因此不可以用在链表等数据结构中

内联inline

inline修饰的函数,叫作内联函数。C++编译器会在调用的地方直接展开内敛函数。它设计的目的就是要平替C语言的宏避免宏的坑

注:define宏函数的使用要点
①宏函数最后,不可加分号

#define ADD(x, y) ((x)+(y));
cout << ADD(1,2) << endl;//会报错,展开后多了个分号

②宏函数需要加内部的括号
③宏函数需要加外部的括号
都是为了避免宏函数展开时,因运算符优先级的问题导致运算顺序没有满足实际需要,从而发生错误
宏函数的好处:函数展开,不需要开辟栈帧但是实现复杂容易出错展开后代码量大不可以调试
内联既保留了不用开辟栈帧的优点,而且没有宏的坑。

在vs编译器的debug版本下,内联默认不展开,inline修饰会忽略,这是为了能够展开调试(展开了就和宏一样无法调试了)。可以设置修改为不分内联函数展开,即只展开短小函数,递归函数等复杂函数不展开。

如图,可设置为简单inline函数展开。

究竟要多复杂的函数才会不展开呢?这取决于编译器自身,不同的编译器在这一点上就不同。在汇编层,不展开的内联函数会有call指令出现。

假设Add函数在汇编层内有100条指令,在工程中调用了10000次
若不展开,汇编层一共只有10000条call指令;
若展开,汇编层一共有100 * 10000条指令。
因此,若展开复杂函数,会让代码量剧增,会导致指令占用内存变多。

且内联函数不建议声明和定义分离在两个不同的文件上,可能会出现链接错误。因为内联函数没有地址。

nullptr

NULL在C++中为int类型的0,在C语言中为空指针,即void*类型。但在C++中void*不可以再转类型,这就导致无法实现泛式函数
nullptr为特殊关键字,可以转换为任意类型的指针,在C++中要用nullptr来定义空指针。

❤~~本文完结!!感谢观看!!欢迎来我博客做客~~❤ 


网站公告

今日签到

点亮在社区的每一天
去签到