目录
1.命名空间
2.输入输出
3.缺省函数
4.函数重载
5.引用
6.inline
7.nullptr
1.命名空间
1.1namespace的价值
在C/C++中,变量、函数和类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的就是堆标识符的名称进行本地化,避免命名冲突或名字污染。
1.2namespace的定义
●定义命名空间,需要使用namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等
●namespace本质是定义出一个域,这个域跟全局域各自独立,不同的域可以定义同名变量
●C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找一个变量/函数/类型出处(声明或定义)的逻辑,所以有了域隔离。局部域和全局域除了会影响编译查找逻辑,还会影响变量的生命周期,命名空间域和类域不影响变量生命周期
●namespace只能定义在全局,还可以嵌套定义
●项目工程中多文件中定义的同名namespace会认为是一个namespace,不会冲突
●C++标准库都放在一个叫std(standard)的命名空间中
namespace Sco{
//命名空间中可以定义变量/函数/类型
int a=0;
void Print(){
cout<<"hello world";
}
struct Node{
struct Node *next;
int val;
};
}
//命名空间可以嵌套
namespace s{
namespace s1{
int a=0;
}
namespace s2{
int a=1;
}
}
//同名的命名空间会合并
namespace M{
void Print();
}
namespace M{
void Print(){
cout<<"hello world";
}
}
1.3namespace的使用
编译查找一个变量的声明/定义时,默认只会在局部或全局查找,不会到命名空间里面取查找。所以我们要使用命名空间中定义的变量/函数:
●指定命名空间访问,项目中推荐
●using将命名空间中的某个成员展开,项目中将此访问的不存在冲突的成员推荐使用这种方式
●展开命名空间中全部成员,项目不推荐,冲突风险很大
//对命名空间某个成员展开
using Sco::Node;
//对整个命名空间展开
using namespace Sco;
int main(){
//指定命名空间访问
cout<<Sco::a;
return 0;
}
2.输入输出
●<iostream>是Input Output Stream 的缩写,是标准的输入、输出流库,定义了标准的输入、输出对象
●std::cin是istream类的对象,它主要面对窄字符(narrow characters(of type char))的标准输入流
●std::out是ostream类的对象,它主要面对窄字符的标准输出流
●std::endl是一个函数,流插入输出时,相当于插入一个换行符加刷新缓冲区
●<<是流插入运算符,>>是流提取运算符
●使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动指定格式,C++的输入输出可以自动识别变量类型(本质是通过函数重载实现的),最重要的是C++的流能更好的支持自定义类型对象的输入输出
●IO流涉及类和对象,运算符重载、继承等多个面对对象的知识
●cout/cin/endl等都属于C++标准库,C++标准库都放在一个叫std(standard)的命名空间中,所以要通过命名空间的使用方式去使用它们
3.缺省函数
●缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参,缺省参数分为全缺省和半缺省参数(有些地方把缺省参数也叫默认参数)
●全缺省就是全部形参都给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省值必须从右往左依次连续缺省,不能间隔跳跃给缺省值
●带缺省参数的函数调用,C++规定必须从左到右依次给实参,不能跳跃给实参
●函数声明和定义分离时,缺省参数不能再函数声明和定义中同时出现,规定必须函数声明给缺省值
4.函数重载
C++支持在同一作用域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或类型不同。这样C++函数调用就表现出多态行为,使用更灵活。C语言不支持同一作用域中出现同名函数
注:
//返回值不同不能作为重载条件,因为调用时叶无法区分
void func(){
}
int func(){
}
//下面两个函数构成重载
//但调用时会出现报错,有歧义,编译器不知道调用谁
void func(){
}
void func(int a=1){
}
5.引用
5.1引用的概念和定义
应用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟空间,它和它引用的变量公用同一块内存空间。
类型& 引用别名=引用对象;
C++中为避免引入太多运算符,会复用C的一些符号,比如前面的<<和>>,这里引用也和取地址使用了同一个符号&。
int main(){
int a=0;
//引用:b是a别名
int &b=a;
b++;
//这是取地址
cout<<&a<<' ' <<a;
return 0;
}

5.2引用的特性
●引用在定义时必须初始化
●一个变量可以有多个引用
●引用一旦引用一个实体,就不能在引用其它实体
注:引用只能引用实体(即变量)
5.3引用的使用
●引用在实践中主要是于引用传参和引用做返回值中减少拷贝提高效率和改变引用对象时同时改变被引用对象
●引用传参跟指针传参功能是类似的,引用传参相对更方便一些
●引用和指针在实践中相辅相成,功能有重叠性,但各有特点,互相不可替代。C++的引用跟其它语言的引用(如Java)是有很大区别的除了用法,最大的点,C++的引用定义后不能改变指向,Java的引用可以改变指向
//也可以返回带引用的函数
int& STTop(ST& rs) {
assert(rs.top > 0); return rs.a[rs.top];
}
5.4const的引用
●可以引用一个const对象,但是必须用const引用。const也可以引用普通对象,因为对象的访问权限在引用过程中可以缩小,但不能放大
●要注意的是类似int &rb=a*3;double d=12.34;int &rd=d;这样一些场景下的a*3和结果保存在一个临时对象中,int &rd=d也是类似(权限缩小),在类型转换中会产生临时对象存储中间值,即引用对象rb和rd引用的都是临时对象,而C++规定临时对象具有常性,所以这里就触发了权限放大,必须要用常引用才行
●所谓临时对象就是编译器需要一个空间暂存表达式的求值结果时临时创建的一个未命名的对象,C++中把这个未命名对象叫做临时对象
const int a=0;
//无法从const int 转化为int &,这是权限放大
//须采用如下用法
const int &ra=a;
//下面是对访问权限的缩小(可以缩小,不能放大)
int b=1;
const int &rb=b
5.5指针和引用的关系
C++中指针和引用就像是两个性格迥异的亲兄弟,在实践中它们相辅相成,功能具有重叠性,但各自有各自的特点,互相不可替代。
●语法概念上引用是一个变量的取别名不开空间,指针是存储一个变量地址,要开空间
●引用在定义时必须初始化,指针建议初始化,但语法上不是必须的
●引用在初始化引用一个对象后,就不能在引用其他对象;而指针可以不断地改变指向对象
●引用可以直接访问指向对象,指针需要解引用才是访问指向对象
●sizeof中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占空间字节个数(32位平台4字节,64位平台8字节)
●指针很容易出现空指针和野指针的问题,引用很少出现,引用使用起来更安全
6.inline
●用inline修饰的函数叫做内联函数,编译时C++编译器会在调用的地方展开内联函数,这样调用内联函数就需要建立栈帧了,就可以提高效率
●inline对于编译器只是一个建议,即即使你加了inline编译器也可以选择在调用的地方不展开,不同编译器关于inline什么情况展开各不相同,C++标准没有规定这个。inline使用于频繁调用的短小函数(如手动实现一个交换函数),对于递归函数,代码相对多一些的函数,加上inline也会被编译器忽略
●C实现宏函数也会在预处理时替换展开,但是宏函数实现很复杂很容易出错,且不方便调试,C++设计了inline目的就是替代C的宏函数
●inline不建议声明和定义分离到两个文件,分离会导致链接错误。因为inline被展开,就没有函数地址,链接时会出现报错
inline int ADD(int x,int y){
return x+y;
}
//宏实现
#define ADD(a,b) ((a)+(b))
7.nullptr
NULL其实是一个宏,子啊传统C头文件<stddef.h>中
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
●C++中NULL可以被定义位字面常量0,C中被定义为无类型指针(void *)的常量。不论采用何种定义,在使用空值的指针时,都会遇到麻烦,如像通过f(NULL)调用指针版本的f(int *)函数,但由于NULL被定义为0,调用了f(int x),因此于程序初衷相悖。且f(void *)NULL);调用会报错
●C++11中引入nullptr,nullptr时一个特殊的关键字,nullptr是一种特殊类型的字面量,它可以转换成任意其他类型的指针类型。使用nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被隐式的转换为指针类型,而不能转换为整数类型