前言:
从本篇文章开始就要正式的学习C++这门语言,C++是Bjarne Stroustrup博士在C语言的基础上引用并扩充了面向对象的概念,容纳了面向对象的编程思想,并增加了许多有用的库,以及编程范式等。
一、C++的关键字
二、命名空间~namespace
1).命名空间的作用
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
2).命名空间的定义
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。在一般开发中,会使用项目的名称作为命名空间的名称。
命名空间中可以嵌套多个小的子空间。
若存在多个相同名称的命名空间:
1、同一个工程中允许存在多个相同名称的命名空间,
编译器最后会合并成同一个命名空间
2、一个工程中的 test.h(头文件) 和 text.cpp(C++文件)中
两个同名命名空间会被合并成一个
注意:一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中
3).命名空间的使用
命名空间的使用有三种方式:
- 加命名空间名称及作用域限定符,作用域限定符(两个冒号)~~ ‘: :’
- 使用using namespace命名空间名称 展开命名空间
使用 using namespace 命名空间名称 可以展开对应的命名空间,展开后可以直接通过该命名空间中成员的名称使用该成员但是使用该方式对命名空间的展开,会导致命名空间的所有内容暴露出来,可能又会导致命名冲突问题。
所以一般在自己使用时为了方便才会使用该方式,如果是项目工程,该方式一定要慎重使用。
- 使用using将命名空间中某个成员引入
使用方式二直接将命名空间展开会有命名冲突的风险,故我们可以通过:
using 命名空间名称::指定成员
来指定只展开命名空间中的某个成员 这种方式是比较常用的,通常是对一些常用的成员(对象)进行使用,来避免频繁使用方式一调用命名空间,减轻代码冗余。
![](https://img-blog.csdnimg.cn/direct/5a7324bac8bd47b482634dbc9400cda5.png)
三、C++输入&输出
在C++中加入了新的输入输出的方式,但由于C++是在C的基础上发展起来的,所以C的输入输出方式在C++中也同样适用。我们先要了解std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中。
std是C++标准库的命名空间,如何展开std使用更合理呢?
1. 在日常练习中,建议直接using namespace std即可,这样就很方便。
2. using namespace std展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对象/函数,就存在冲突问题。
说明:
1. 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件以及按命名空间使用方法使用std。
2. cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含< iostream >头文件中。
3. << 是流插入运算符,>>是流提取运算符。
4. 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。C++的输入输出可以自动识别变量类型。
5. 实际上cout和cin分别是ostream和istream类型的对象,>>和<<也涉及运算符重载等知识。
#include<iostream>
// 指定展开命名空间成员
using std::cout;
using std::cin;
using std::endl;
int main()
{
int a = 10;
double b = 125.3;
// cout和cin是全局的流对象,endl是特殊的C++换行符号
cout << a << endl << b << endl;
printf("%d\n", a);
printf("%0.2lf\n", b);
// cout/cin不需要像printf/scanf输入输出时那样,需要手动控制格式。
// C++的输入输出可以自动识别变量类型。
cout << "对a和b进行修改" << endl;
cin >> a >> b;
cout << a << endl << b << endl;
return 0;
}
四、缺省参数
1). 缺省参数概念
缺省参数是声明或定义用函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采该形参的缺省值,否则使用指定的实参。
但缺省参数不能同时在函数声明和定义中出现。
void Func(int a = 0)
{
cout << a << endl;
}
int main()
{
Func(); // 没有传参时,使用参数的默认值
Func(10); // 传参时,使用指定的实参
return 0;
}
2).缺省参数分类
- 全缺省参数
- 半缺省参数
注意:
1. 半缺省参数必须从右往左依次来给出,不能间隔着给
2. 缺省参数不能在函数声明和定义中同时出现
//a.h
void Func(int a = 10);
// a.cpp
void Func(int a = 20)
{}
// 注意:如果声明与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该用那个缺省值。
3. 缺省值必须是常量或者全局变量
4. C语言不支持(编译器不支持)
五、函数重载
1). 函数重载概念
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。
- 参数类型不同
注:
Add(10, 3.14);
Add(3.14, 10);
如果Add函数传参传入一个整数一个浮点数,就会报错,因为编译器可以将类型进行转化,将int转为double或者将double转为int类型,那么这时这个Add函数不知道应该调用上面两个中的哪一个,就会产生冲突。
- 参数个数不同
编译器可以根据传入的参数自动匹配对应的重名函数。
void f(int a)
{
cout << "f(int a)" << endl;
}
void f(int a = 10)
{
cout << "f(int a = 10)" << endl;
}
int main()
{
f();
f(20);
return 0;
}
若使用了缺省参数就会产生冲突,因为当调用没有传参的函数时,既可以是对应最上面的函数,也可以是下面那个函数,前面的缺省参数学习过,当没有传参时,默认使用缺省值,所以产生了歧义。
- 参数类型顺序不同
2). C++支持函数重载的原理--名字修饰(name Mangling)
在主函数的执行过程中要经历:
预处理 => 编译 = > 汇编 = > 链接
Func.h
Func.cpp
Test.cpp
预处理 :头文件展开/宏替换/条件编译/去掉注释...
Func .cpp => Func.i Test.cpp => Test.i
Func.i 函数声明和定义,Test.i 函数的声明和实际调用
编译:检查语法,生成汇编代码
Func .i => Func.s Test.i => Test.s
汇编:转换成二进制的机器码
Func .s => Func.o Test.s => Test.o
链接:合并到一起,链接一些没有确定函数地址等等
Func .s + Test.s => a.out
在C语言中,没有重载函数,即函数名唯一的情况下,要找函数地址只需要通过唯一的函数名即可找到,即在链接过程中通过唯一的函数名在 Func.o目标文件 中的符号表进行对地址的查找,所以如果C语言中有重载函数,函数名不唯一的情况下就无法在链接过程中找到函数地址,因此C语言无法支持重载函数。
C++支持重载函数的原因 -- 名字修饰(name Mangling):
(注:不同编译器实现方式不同,这里以Linux中的g++为例)在C++中有重载函数的情况下,即函数名不唯一的情况下,C++有一个函数,可以通过函数名和参数情况修饰出一个新的函数名字,函数名相同但参数情况不同,就能修饰出不同的函数名字,再通过修饰出的函数名字来查找对应的函数地址。
Linux下g++的修饰名字构成方式:
_Z + 函数名字符个数 + 函数名 + 各参数首字母
假设有一个函数:Add(int a, double b) ,修饰后的函数名字为:_Z3Addid
假设有另一个函数:Add(double b, int a) ,修饰后的函数名字为:_Z3Adddi
所以即使函数名相同,也可以通过参数情况来创建出不同的函数名字。