目录
C++关键字(C++98)
命名空间的三种方式
1.指定,加命名空间名称及作用域限定符
2.展开常用的,使用using引入命名空间中的成员
3.全部展开,使用using namespace引入命名空间名称
缺省参数
函数重载
引用
内联函数
auto关键字
nullptr
C++总共63个关键字,C语言32个
命名空间主要解决名字冲突,作用就是定义一个新的作用域
namespace ps
{
int rand = 0;
}
int main()
{
printf("%d\n", ps::rand);
return 0;
}
namespace gf
{
int rand = 0;
int sqrtt = 1;
}
using gf::sqrtt;
int main()
{
printf("%d\n", sqrtt);
return 0;
}
namespace gf
{
int rand = 0;
int sqrtt = 1;
}
using namespace gf;
int main()
{
printf("%d\n", sqrtt);
return 0;
}
全部展开相当于把这个命名空间暴露在全局域中,命名冲突的风险更大
建议:
1.项目中,尽量不要使用using namespace std;
2.日常练习用using namespace std;
3.项目中,指定命名空间访问+展开常用
缺省参数是声明或定义函数时为函数的参数指定一个默认值
在调用有缺省参数的函数时,如果没有指定实参则采用该默认值,否则使用指定实参
如果没有传参数,缺省参数就会起作用
void Func(int a = 0)
{
cout << a << endl;
}
int main()
{
Func();
}
半缺省,必须从右往左连续缺省,不能间隔
void Func(int a, int b = 20; int c = 30)
{
}
缺省参数不能在函数声明和定义中同时出现
分离定义时:声明给缺省参数
C++允许同一作用域声明功能类似的同名函数
这些同名函数形参列表(参数个数 或 类型 或 顺序)必须不同
int Add(int p1, int p2)
{
}
int Add(int p1, double p2)
{
}
int Add(double p1, int p2)
{
}
注意:返回值不同并不构成重载
C++有函数名修饰规则所以支持重载
C++函数名修饰规则是拿函数名+参数类型的首字母去调用(不同编译器可能会有所不同)
而C语言是直接拿函数名去调用,所以不支持
引用给已存在的变量取一个别名,编译器不会为引用变量开空间
类型& 引用变量名 = 引用实体;
//给a取个别名b
int main()
{
int a = 0;
int& b = a;
}
int a = 1;
//int& b; //1.引用在定义时必须初始化
int& b = a; //2.一个变量可以有多个引用
int& c = a;
int& d = c;
//引入一旦引用一个实体,就不能引用其他实体
引用的好处
//做输出型参数
void Swap(int& p1, int& p2)
{
int tmp = p1;
p1 = p2;
p2 = tmp;
}
int main()
{
int a = 0, b = 2;
Swap(a, b);
}
注意:出了函数的作用域,返回对象就销毁了
那么一定不能用引用返回,要用传值返回
int Count() //传值返回
{
int n = 1;
return n;
}
int& Count() //引用返回
{
int n = 1;
retrun n;
}
传值返回会统一生成一个返回对象临时拷贝作为函数调用返回值
返回对象临时拷贝会随着函数调用的结束而销毁
如果返回值小拷贝会放到寄存器里面
寄存器只能存4/8个字节
如果大会在main函数里面提前开好空间
下面就可以使用引用返回,把q放到静态区,就不会随着函数调用的结束而销毁
int& Count()
{
static int q = 1;
return n;
}
引用权限不能放大,但是可以缩小
不同类型间的赋值会先创建一个临时变量
而临时变量具有常性,所以被赋值的变量必须加const
(常性指变量所属类型是否为const或volatile类型)
const引用具有很强的接收度,如果使用引用传参,函数内不改变传过来的参数,那么建议尽量用const引用传参
引用和指针的不同
1.引里在定义时必须初始化,指针没有要求
2.引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
3.没有NULL引用,但有NULL指针
4.在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
5.引用自加即引用的实体增加1,指针自加即指针向后偏移一全类型的大小
6.有多级指针,但是没有多级引用
7.访问实体方式不同,指针需要解引用,引用编译器自己处理
8.引用比指针使用起来相对更安全
引用表面好像是传值,其本质也是传地址,只是这个工作由编译器来做 (某大厂有考过)
概念:以inline修饰的函数叫内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率
适合短小的函数(1-10行)且频繁调用(10万次)
适合场景:堆排和快排,排序10w数据,里面swap函数
C的宏函数的优点:a、复用性变强 b、宏函数提高效率,减少栈帧建立
宏函数的缺点:a、可读性差 b、没有类型安全检查 c、不方便调试
而C++ inline的出现便是用来替换C的宏函数,解决宏函数缺点的同时兼顾宏函数的优点
//inline 符合条件的情况,在调用的地方展开
inline int Add(int a, int b)
{
return a + b;
}
C++中不建议使用宏,尽量使用const,enum,inline替换宏
1.inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的函数不宜使用作为内联函数
2.inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有函数内部实现代码指令长度比较长(10行左右)/递归等等,编译器优化时会忽略掉内联。
3.inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。(建议在声明里面定义)
auto的原理就是根据后面的值,来自己推测前面的类型是什么。
auto的作用就是为了简化变量初始化,如果这个变量有一个很长很长的初始化类型,就可以用auto代替
在声明符列表中,“auto”必须始终推导为同一类型
//auto x1 = 5, x2 = 3.0, x3='s';
auto = 3.0, 5.5, 6.3;
例如:
std::vector ve;
std::vector::iterator it = ve.begin();
// 可以用auto代替初始化类型:
auto it = ve.begin();
int main()
{
int a[] = { 1,2,3,4,5 };
for (auto& s : a)
{
s--;
std::cout << s << " ";
}
return 0;
}
注意:1.用auto声明的变量必须初始化(auto是根据定义的值自动匹配变量类型,如果后面没有值,就会报错)
2.函数和模板参数不能被声明为auto(原因同上)
3.因为auto是一个占位符,并不是一个他自己的类型,因此不能用于类型转换或其他一些操作,如sizeof和typeid
4.定义在一个auto序列的变量必须始终推导成同一类型
5.auto不能作为函数参数类型,也不能作为数组类型
NULL是一个宏定义,而nullptr是C++的一个关键字
C++新标准中建议使用nullptr代替NULL来声明空指针
因为在早期设计 NULL 空指针时,NULL 实际上就是 0,所以导致有些地方使用 NULL 会造成不明确的函数调用
void Coun(char *){}
void Coun(int){}
int main()
{
Coun(NULL); // 调用Conc(int)
}
我们经常用NULL来初始化空指针,从惯性思维看,Coun应该调用的是void Coun(char *)
但C++中NULL的值是0,所以调用的是void Coun(int)。考虑如上问题,nullptr关键字便引入了。
nullptr关键字用于标识空指针。它可以转换成任何指针类型和bool布尔类型(主要是为了兼容普通指针可以作为条件判断语句的写法),但是不能被转换为整数。