✨前言✨
博客主页:to Keep博客主页
欢迎关注,点赞,留言评论
⏳首发时间:2023年10月19日
博主码云地址:博主码云地址
参考书籍:《C++ Primer》《C++编程规范》
编程练习:牛客网+力扣网
由于博主目前也是处于一个学习的状态,如有讲的不对的地方,请一定联系我予以改正!!!
在C语言中,我们可能会遇到命名冲突问题,例子如下:
当我们没有使用stdlib库时,代码是可以正常运行的,而使用stdlib库时,我们的程序使用不了。原因就是我们所定义的变量名字与stdlib中有个rand函数名字冲突了,导致代码不可以正常运行,所以C++中就引入命名空间这一概念,来解决命名冲突。
我们通常使用namespace关键字来实现,命名空间就是起着隔离作用域,但是里面的内容是属于全局变量内容(命名空间就是类似的加了一堵墙),我们通常要使用域作用符(::
)来进行访问(把墙打开)。通俗点来讲就是可以将库里面和自己命名所冲突的分隔开,不会出现冲突,让代码可以继续运行。
namespace 命名空间的名字
{
......(可以包含变量,结构体等内容,甚至还可以继续嵌套命名空间)
}
需要注意的是相同名字的命名空间是会合并在一起的,如果我们在写声明与定义的时候,只需要用相同的名字的命名空间涵盖起来就可以了
在C++中,我们使用iostream这个输入输出库,不用像C语言一样头文件带.h。C++标准库的内容全在std这个命名空间里面,我们得利用std进行访问,利用using关键字进行展开命名空间(类似于没有那堵墙了)。
全部展开其实就又会出现我们之前讲过的命名冲突的问题了,所以我们一般将常用的函数或者变量进行命名空间局部的展开就可以!
是指在函数声明以及定义的时候,在参数列表中给定一个缺省值,如果实参有数据传过来,就以实参的数据为准,否则默认缺省值。
1 半缺省参数必须从右往左给定,并且不可以间隔
2 缺省参数不可以在函数的声明与定义中同时出现
3 缺省值必须是常量或者是全局变量
是指函数名相同,但是参数列表个数,类型不同。与返回值无关!
C语言是不支持重载的,那是因为C语言在编译链接的时候是根据函数名直接去寻找地址的,所以它就不支持函数名同名的。而C++底层在编译链接的时候对函数名进行了特别的处理,加上了一些内容,这样就可以找到函数名相同,但是参数不同的那个所需要的函数了!具体的解释可以参考这篇文章:C++如何支持重载
引用的本质:就是给变量取别名,和变量用的是同一块内存空间。例子如下:b就是一个引用
内存空间示意图如下:
1 引用必须进行初始化
2 一个变量可以有多个引用
3 引用一旦确定一个实体,是不可以进行改变的(所以在C++中,对于链表的操作,我们依旧采用指针的方式)
我们以下面这段代码为例:
我们知道在C语言中,我们必须传指针才可以交换两个变量之间的值,因为形参只是实参的拷贝!而在C++中,我们利用引用作为参数,作为实参的别名,指向的是同一块内存空间,所以就可以顺利的交换变量之间的值了!
我们先来看这样一段代码
int& ADD(int x,int y)
{
int tmp = x + y;
return tmp;
}
int main()
{
int& ret = ADD(1,2);
cout << ret << endl;
return 0;
}
你认为ret打印出来是多少呢?如果你认为是3,那么恭喜你,成功的答错了这道题!正确的答案其实应该是随机值:
注:对于函数开辟空间的问题,具体可以参考这篇文章:函数的栈帧
我们在看这段代码:
int& Count(int x,int y)
{
static int n = x + y;
return n;
}
int main()
{
int& ret = Count(1, 2);
cout << ret << endl;
int& ret1 = Count(2, 3);
cout << ret1 << endl;
return 0;
}
你觉得ret和ret1打印出来各是多少呢?如果你以为是随机值!!!那么恭喜你又成功的答错了,因为此时的n是静态变量,它所在的位置不是位于函数中,而是在一个叫做静态区的位置,所以此时ret是一个确定的值,而由于对于变量,只可以初始化一次,所以ret1是等于ret的值的!!!
所以我们在使用引用作为返回值时,我们需要特别注意引用的地方内存是否会被清除!以下面这个例子为例,说明一下引用的用法,后续还会进一步的反复学习!!!
int& arraypos(SL* ps,int pos)
{
return ps->a[pos];
}
int main()
{
SL a;
for (int i = 0; i < a.size; i++)
{
//让顺序表中的值都加1
arraypos(&a, i)++;
}
}
举几个例子来理解一下常引用:
接下来我们在理解一下这个代码:
这里需要说明一点的就是,当类型不一样时,是会发生类型转换的,而不管是强制类型转化还是隐性类型转化,其实都是会中途产生一个临时变量,而这个临时变量具有不可改变的性质也就是常性(也可以理解为是一个确定的数字,是一个常数),所以加了const才不会报错
图解:
1 指针是可以不初始化的,而引用必须初始化
2 引用是不可以更改实体的指向,而指针是可以的
3 引用是变量的别名,而指针是存储变量的地址
4 引用不可以为NULL,而指针可以为NULL
5 不存在多级引用,存在多级指针
6 引用自增是实体加1,而指针加1是偏移一个类型的大小
7 访问实体方式不同,引用编译器自己会进行处理,而指针需要显式的解引用
8 在sizeof中的含义不同,引用表示类型的大小,而指正是固定的4个字节(32位平台下)或8(64位平台下)个字节
9 总体而言,引用相比较于指针更加安全!
内联函数的概念:用inline关键字修饰的函数叫做内联函数,并且编译时会在调用内联函数的地方展开!这样就会没有函数栈帧的开销,提高了程序运行的效率!
内联函数其实主要解决C语言中宏的缺点
我们可以先来看一段宏定义的代码:
宏的缺点:
1 宏是不方便进行调试的,因为在预编译阶段就进行了替换
2 代码的可读性比较差,难以理解
3 没有类型安全检查机制
优点:
1 可以不用开辟栈帧,提高代码的运行效率
2 增强代码的复用性
C++中就利用内联函数(兼容了宏的优点也克服了它的缺点)代替宏,常量定义用const enum来代替
1 inline对于C++编译器来说只是一个建议,适合于规模较小且使用频率高的函数,但不可以是递归!否则规模较大或者是递归,即使你使用了inline关键字去修饰函数,那么C++编译器会无视!!!
2 内联函数的定义和声明是不可以分开的!这是因为inline被展开,就会没有函数地址,这样链接的时候就找不到了!!!
可以自动识别类型,后续我们如果遇到很长的类型是,可以使用auto关键字,所以这就要求使用auto时,必须进行初始化!!!
我们从以上可以看出,使用auto关键字时,auto与auto*没有任何区别,并且引用类型必须要用&来声明!!!
1 auto不可以作为函数的参数
2 auto不能用来声明数组
我们先来看以下这段代码:
void func(int a)
{
cout << "int a" << endl;
}
void func(int* a)
{
cout << "int* a" << endl;
}
int main()
{
//func(1)
func(NULL);
return 0;
}
你认为运行的结果是什么呢?其实答案是int a并不是int* a,为什么会这样呢?那是因为编译器默认情况下会将NULL认为字面常量为0,如果要成为指针空值,那么必须强制转化(void*)0。所以就会调用第一个func,所以在C++中就引入nullptr关键字作为指针空值
总结:
本篇文章主要学习了C++入门的一些基础知识,后续我们将继续深入的学习C++中的语法知识!