一、命名空间
#include<iostream> using namespace std; int main() { cout << "hello world" << endl; return 0; }
相信大家学习C++肯定都写过这个hello world的程序吧,第二行代码using namespace std;即是用到了所谓的命名空间。
命名空间语法:namespace 空间名{...}
命名空间概述:命名空间存在的意义即是避免函数,类,变量等的命名冲突。其本质就是框起来了一块区域,其与外部隔开,类似于重新划定作用域的存在。
命名空间的性质:
- 命名空间支持嵌套
- 同一个工程可以有多个同名的命名空间(在编译时它们会被合成一个命名空间)
命名空间的使用:
- 命名空间名称+作用域限定符(名称::)
namespace N{ int a = 10; } int main() { cout << N::a << endl; return 0; }
- 使用using将命名空间的成员引入
namespace N{ int a = 10; } using N::a; int main() { cout << a << endl; return 0; }
- 使用using namespace将命名空间展开
namespace N{ int a = 10; } using namespace N; int main() { cout << a << endl; return 0; }
使用命名空间的注意事项
- 在日常练习时全部展开即可:using namespace std;
- 项目中尽量不要这样使用using namespace std;
- 在项目中使用指定空间名访问+常用展开(如std::cout)
二、缺省参数
C++中支持函数在声明或定义时,给形参列表里的变量赋初始值
我们可以看到,当没有传参时则会使用缺省值,如果传了参数则使用实参的值
函数缺省参数还分为了全缺省与半缺省
- 全缺省即全部的参数都给了初始值
- 半缺省则是自右至左给了初始值(没有间隔的赋值)
![]()
什么是没有间隔,即从右至左必须连着给定初始值(如下即是错误的)
三、函数重载
函数重载即是多个同名函数但形参列表并不相同的语法形式。
int Add(int left, int right) { return left + right; } double Add(double left, double right) { return left + right; } long Add(long left, long right) { return left + right; }
函数重载的要求
- 形参列表参数个数不同
- 形参列表参数顺序不同(相同类型的参数其顺序不同)
- 形参列表参数类型不同
只是返回类型不同的函数不能发生重载
总结来说就是可以让编译器区分自己该调用哪个函数即可
这里有一个小知识点:为什么C++支持重载,为什么C语言不支持?
C++和C语言对函数的处理方式:
- C语言底层是直接通过函数名去找到函数地址并执行的,如果函数同名则会冲突,有矛盾
编译时会通过函数名生成符号表,符号表记录着相当应函数名对应的函数地址,若同名则会生成矛盾- C++底层的函数名修饰规则是函数名+参数类型,所以当参数类型(顺序等)不同时则会生成不同的函数名
本质原因就是因为二者语言底层对函数的命名规则区别
在C++中,可以使用exterc "C"{...}来使用C语言的处理方式
四、引用
引用其实本质就是对C语言中的指针进行的封装
但在语法角度而言,引用是并无开辟额外的空间的,其只是变量的一个“别名”(另起一个名字而已,并未开辟空间)
关于引用的使用
- 做参数传参:输出型参数、大数据传参
- 做返回值(类似于返回指针)
- 传值返回:总是会返回一个临时拷贝对象,不返回对象本身
- 传引用返回:返回这个对象的别名(也就是这个对象本身)
如果函数返回时,返回的对象只有在堆区或静态区开辟的才可进行返回- const类型的数据只能取const类型的别名(权限只能平移与缩小,不能放大)
- 在进行类型转换时都会产生一个临时变量(具有常性),然后对该临时变量进行类型转换后赋值(即强转并不会改变数据原本的类型)
ps:因为临时变量具有常性,所以当要初始化引用时,如果要初始化的值需要进行类型转换,则该引用则需要用const修饰(例如:const double& a = 1;)tips:const修饰的引用具有很强的接收性,即如果使用引用传参,函数内部如果不改变参数本身,则尽量使用const进行引用传参
五、内联函数
inline关键字:该关键字修饰的函数则被称为内联函数
内联函数的作用:当函数被inline关键字修饰时,则是建议编译器该函数在调用处直接展开,无需用call指令调用函数,以减少压栈操作的时间消耗,是以空间换时间的做法。
(类似于宏函数的替换,但比宏函数更具实用性)
何为建议编译器展开?即当编译器认为不符合展开条件时则不展开,如:
- 内联函数本身转换为汇编指令后篇幅较长
- 内联函数内存在循环或者递归
宏函数的优缺点
优点:
- 提高了代码的可维护性
- 提高效率,减少栈帧的消耗
缺点:
- 复杂,可读性差
- 不具备类型检查
- 无法进行调试
内联函数基本是完善了宏函数的缺点,也包含了宏函数的优点
tips:
使用内联函数时,声明和定义不要分离,否则会导致链接错误
因为内联函数是直接展开的,故内联函数一般不被编译器放到符号表里。当声明和定义分离时,函数调用处检查到声明,且为内联,但无法展开,此时则会去call函数地址,找函数的定义,但由于内联函数不在符号表里,故此找不到函数的定义则会导致链接错误。
六、auto关键字以及nullptr
- auto关键字
- 在基于范围for中使用时,本质只是对迭代器进行的封装
tips:基于范围的for循环在使用时,其迭代的范围必须是确定的,否则无法使用- 在基于范围for中时,auto只可进行值或者引用的替换,如:auto/auto&
不可用于指针的替换,如:auto*- auto无法声明数组或作为形参类型
- auto作为形参类型时,函数在依据命名规则生成符号表中的函数名时,则无法推导出具体类型。
- nullptr
- C++中的空指针,由于C语言中的NULL本质是(void*)0,在C++中NULL被定义为0,
故此使用nullptr代替原先的空指针