前言
本系列文章承接C语言的学习,需要++有C语言的基础++ 才能学会哦~
第3篇主要讲的是有关于C++的++引用类型++ 、++内联inline++ 和++nullptr++ 。
C++才起步,都很简单呢!
目录
引用类型
即对++同一块++ 连续存储空间,++多取一个标识符(别名)++ ,++语法上++不开辟空间(但是汇编底层也是用指针实现的)
基本语法
cpp
int a = 0;
int& b = a;
如上,引用类型的定义方式为:++类型& 引用别名 = 引用对象++ ("类型",要与引用对象相同)。
这里表示引用b为a的++别名++ 。
引用类型变量同原变量指向同一空间,即a,b都指向同一块空间。
cpp
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;
而且,可以++给别名起别名++(如上代码)。
一个变量可以++有多个别名++。
特性
①引用在定义时++必须初始化++ 。
②一个变量**++可以有多个别名。++**
③引用++不可以再改变指向。++
应用
引用传参和引用做返回值的时候**++减少拷贝++** ,从而提高效率。而且**++改变引用类型对象同时会改变被引用对象++**。
cpp
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对象,不可被赋值,必须初始化)
基本语法
cpp
const int a = 0;
const int& b = a;
引用const对象,要使用const引用。否则·······
这是一个关于访问权限的问题(指针和引用才有)。
cpp
访问权限演示
//①
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宏函数的使用要点
①宏函数最后,不可加分号
cpp#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来定义空指针。++
❤~~本文完结!!感谢观看!!欢迎来我博客做客~~❤