目录
一、命名空间
1.命名空间的作用
c++语法是在c语言的不足之上的弥补,其中命名空间就是一个。
如下:
我们在定义变量或写函数声明时对变量所命的名称可能在某些头文件中被定义过,导致语法错误,这是难以避免的。或者在做项目时需要把多个人写的代码整合在一起,那么各个人之间可能用同样的名称去定义变量,很容易导致重定义问题。所以c++引入了命名空间的概念。
2.命名空间的定义
定义命名空间,需要使⽤到namespace关键字,后⾯跟命名空间的名字,然后接⼀对{}即可,{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
namespace本质是定义出⼀个域,这个域跟全局域各⾃独⽴,不同的域可以定义同名变量,因为域名就可以区分它们。
C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑,还会影响变量的⽣命周期,命名空间域和类域不影响变量⽣命周期。
namespace只能定义在全局,当然他还可以嵌套定义。
项⽬⼯程中多⽂件中定义的同名namespace会认为是⼀个namespace,不会冲突。
C++标准库都放在⼀个叫std(standard)的命名空间中。
3.命名空间的使用
要得到命名空间的某个成员变量只需要以下格式
命名空间的名字 :: 成员名
使用using可以把命名空间展开,即成员变量不在受命名空间域的限制,可以直接访问。using还可以对某个成员变量展开。具体示例如下:
二、输入输出
1.输出运算符<<
c++的输入输出通常用cin,cout,例如输出Hello world
-
#include<iostream>
-
int main()
-
{
-
std::cout<<
"Hello world"<<std::endl;
-
return
0;
-
}
<<是一个运算符重载(就是一个运算符可以表示多个意思),<<也可以表示位运算。
左操作数:ostream对象
右操作数:需要打印的内容
返回值:ostream对象
结合方向:自左向右
<<可以自动识别数据类型,不需要向printf一样显示的表示。如下:
-
#include<iostream>
-
int main()
-
{
-
int a=
10;
-
std::cout<<a;
-
return
0;
-
}
endl的作用之一是换行在这里可加可不加。
当然运算符<<是无法完成printf的某些功能的,还需两着相互配合使用。
2.输入运算符>>
>>也是一个运算符重载(就是一个运算符可以表示多个意思),>>也可以表示位运算。
左操作数:istream对象
右操作数:需要输入的变量
返回值:istream对象
结合方向:自左向右
>>可以自动识别数据类型,不需要向scanf一样显示的表示。如下:
-
#include<iostream>
-
int main()
-
{
-
int a=
0;
-
std::cin>>a;
-
return
0;
-
}
同样运算符>>是无法完成scanf的某些功能的,还需两着相互配合使用。
为了方便我们还可以把命名空间给展开,如下:
-
#include<iostream>
-
using
namespace std;
-
int main()
-
{
-
int a=
0;
-
cin>>a;
-
return
0;
-
}
三、缺省参数
在写函数形参的时候我们可以添加一个缺省值,这样在使用这个函数的时候即使不传参也能调用它会使用缺省值来代替实参。如下:
-
#include<iostream>
-
int add(int a=0,b=1)//0为a的缺省值,1为b的缺省值。
-
{
-
return a+b;
-
}
-
int main()
-
{
-
add();
-
add(
1);
//这里的1传给的是第一个形参,即a
-
add(
1,
2);
-
return
0;
-
}
add()的这三种调用方式都是合法的。
缺省参数分为全缺省和半缺省参数。(缺省参数也叫默认参数)
全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值。
带缺省参数的函数调⽤,C++规定必须从左到右依次给实参,不能跳跃给实参。
函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值。
四、函数重载
函数重载就是使用相同的函数名写多个函数实现不同的功能,这个在c语言语法上是不允许的,但在C++上是可以的,但要求要有能够区分它们的形参。如:
-
#include<iostream>
-
int add(int a,int b)
-
{
-
return a+b;
-
}
-
double add(double a,double b)
-
{
-
return a+b;
-
}
-
int main()
-
{
-
int c=
add(
12,
5);
-
double d=
add(
1.2,
3.6);
-
return
0;
-
}
这里虽然写了两个函数名相同的函数,但编译器可以根据所传参数联系来区分应该调用哪一个函数,所以是合法的,这就是函数重载。
重载函数的参数可以做一下设置(1).参数类型不同(2).参数个数不同(3).参数类型顺序不同
在这里fu(2)是合法的,编译器知道要调用第一个fu,而fu()则是不合法,因为编译器无法知道要调用哪一个fu,所以函数重载最核心的问题还是通过控制参数来让编译器来识别需要调用哪一个函数, 注意编译器只看参数,去控制返回值类型没有用。
五、引用
1.引用简介
初学引用我们可以把它理解为别名,它的作用和指针差不多这是引用更方便而已。
引用格式:
类型& 引⽤别名 = 引⽤对象;
如下:
-
#include<iostream>
-
int main()
-
{
-
int a=
6;
-
int& p=a;
-
return
0;
-
}
引⽤在实践中主要是于引⽤传参和引⽤做返回值中减少拷⻉提⾼效率和改变引⽤对象时同时改变被引⽤对象。
引⽤传参跟指针传参功能是类似的,引⽤传参相对更⽅便⼀些。
引⽤和指针在实践中相辅相成,功能有重叠性,但是各有特点,互相不可替代。
2.引用的注意事项
- 引⽤在定义时必须初始化
- ⼀个变量可以有多个引⽤
- 引⽤⼀旦引⽤⼀个实体,再不能引⽤其他实体
3.const引用
在引用一个const对象时一定也要用const修饰,如果不用const修饰就属于权限放大问题(本来const修饰的变量不能被修改而引用没有用const修饰即可以被修改,权限放大),不符合语法。
需要注意的是类似 int& rb = a*3; double d = 12.34; int& rd = d; 这样⼀些场景下a*3的和结果保存在⼀个临时对象中, int& rd = d 也是类似,在类型转换中会产⽣临时对象存储中间值,也就是时,rb和rd引⽤的都是临时对象,⽽C++规定临时对象具有常性,所以这⾥就触发了权限放⼤,必须要⽤常引⽤才可以。最核心的就是在引用对象时权限可以被缩小但不能被放大。
所谓临时对象就是编译器需要⼀个空间暂存表达式的求值结果时临时创建的⼀个未命名的对象,C++中把这个未命名对象叫做临时对象。
4.引用与指针的关系
- 语法概念上引⽤是⼀个变量的取别名不开空间,指针是存储⼀个变量地址,要开空间。
- 引⽤在定义时必须初始化,指针建议初始化,但是语法上不是必须的。
- 引⽤在初始化时引⽤⼀个对象后,就不能再引⽤其他对象;⽽指针可以在不断地改变指向对象。
- 引⽤可以直接访问指向对象,指针需要解引⽤才是访问指向对象。
- sizeof中含义不同,引⽤结果为引⽤类型的⼤⼩,但指针始终是地址空间所占字节个数(32位平台下占4个字节,64位下是8byte)
- 指针很容易出现空指针和野指针的问题,引⽤很少出现,引⽤使⽤起来相对更安全⼀些。
六、inline
(1).inline修饰的函数称为内联函数,它的作用是把被修饰的函数直接展开而不用去建立函数栈针。有点类似宏函数的效果,它的设计目的就是为了替代宏函数,因为宏函数在处理的时候需要注意的详解太多了,很容易出错。
内联函数的定义,示例如下:
(2).inline对于编译器⽽⾔只是⼀个建议,也就是说,就算是加了inline编译器也可以选择在调⽤的地⽅不展开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定这个。inline适⽤于频繁调⽤的短⼩函数,对于递归函数,代码相对多⼀些的函数,加上inline也会被编译器忽略。
(3).vs编译器debug版本下⾯默认是不展开inline的,这样⽅便调试,debug版本想展开需要单独的做设置。
(4).inline不建议声明和定义分离到两个⽂件,分离会导致链接错误。因为inline被展开,就没有函数地址,链接时会出现报错。