C++语法学习之路
C++语法学习之路
C++ 是在 C 的基础之上,容纳进了面向对象编程思想,并增加了许多有用的库,以及编程范式等。前期的 C++ 主要是在补充 C 语言的不足,以及对 C 设计不合理的地方进行优化。
一、关键字
C++ 有63个关键字,C 语言只有32个关键字。C++ 在 C 语言的基础之上增加了更多的关键字。
关于这些新增的关键字,我们不需要一下子就去全部搞懂。在学和用的过程中,我们慢慢就会熟能生巧了。
auto 关键字
auto
类型,能根据右边的表达式自动推导表达式的类型。在类型名比较长的时候有很大的作用。
int a = 1;
auto b = a;
auto c = a + 1.1;
NULL 与 nullptr
// C语言
#define NULL 0
// C++
#define nullptr ((void*)0)
二、命名空间 namespace
命名空间主要解决命名冲突的问题。命名冲突可能会是我们写的变量函数和调用的库冲突了,也可能是和同事的变量函数命名冲突了,导致编译不通过。
如果是使用 C 语言,我们只能去修改冲突的变量函数名。C++ 加入了命名空间以后就解决了这个问题。
命名空间增加了命名空间域的概念,其他域还有类域(class)、局部域、全局域。同时还加入了 ::
(域作用限定符)。变量和函数只会在自己的域内发挥作用,通过 ::
在其他域中引用需要的域变量函数。
// 全局域
int a = 0;
// 命名空间域A
namespace A
{
int a = 2;
} // 不能给分号
int main()
{
// 局部域
int a = 1;
// ::的前面是跟的域名,后面则是变量函数名
// 空代表的是全局域
printf("%d\n", a);
printf("%d\n", ::a);
printf("%d\n", A::a);
return 0;
}
# cmd 命令输出
1
0
2
使用 using namespace
展开命名空间域后,就会把命名空间域里的代码暴露到其他域。这时全局域下的变量 a
和**命名空间域 A **下的变量 a
会冲突。
所以我们一般不要直接把命名空间域展开,这会出现许多问题。而是通过域作用限定符 ::
去调用命名空间域中的变量函数。
int a = 0;
namespace A
{
int a = 1;
}
// 解注下面代码,此时爆红 "a" 不明确
// using namespace A
int main() {
std::cout << a << std::endl;
std::cout << A::a << std::endl;
return 0;
}
命名空间嵌套
命名空间域是可以嵌套的。调用嵌套命名空间里的变量函数需要先从外层开始调用。
namespace A
{
int a = 2;
namespace B
{
int a = 2;
}
}// 不能给分号
printf("%d\n", A::B::a);
命名空间合并
多个同名的命名空间会被合并属于同一个命名空间,不能有同名变量函数。
namespace A
{
int a = 2;
}
namespace A
{
int b = 1;
}
C++标准库和命名空间的关系
传统的 C 语言标准库都是以 .h
结尾的头文件( #include <stdio.h>
)。在 C++ 早期,C++ 的标准库也是以 .h
结尾的。但是在加入命名空间以后 C++ 的标准库不再使用 .h
结尾,并且把标准库里的东西全部加入到了一个命名空间中,名为 std
。
// C 头文件
#include <stdio.h>
// C++ 早期头文件
#include <iostream.h>
// C++ 头文件
#include <iostream>
using namespace std;
C++ 标准库中写的代码都是放在一个同名为 std
的命名空间域中的。
#include <iostream>
namespace std
{
// iostream库的代码
}
#include <list>
namespace std
{
// list库的代码
}
#include <vector>
namespace std
{
// vector库的代码
}
所以如果你想使用 C++ 的标准库,你不但要去包含头文件还需要在使用的地方限定标准库的命名空间 std
。
#include <iostream>
int a = 1;
std::cout << a << std::endl;
// 展开常用的std元素
using std::cout;
using std::endl;
cout << a << endl;
三、C++ 的输入输出
C++ 的输入输出使用了IO流。cplusplus.com/reference 这是 C++ 标准库的文档,里面包含了IO流的介绍。
使用 cout
标准输出对象(控制台)和 cin
标准输入对象 (键盘) 时,必须包含 <iostream>
头文件并在使用的地方展开 std
。<<
是流插入运算符,>>
是流提取运算符。
#include <iostream>
using namespace std;
int a = 2024;
int main()
{
cout << "Hello Word!" << " " << a << endl;
int b = 0;
cin >> b;
cout << "Hello Word!" << " " << b << endl;
return 0;
}
# cmd 命令输出
Hello Word! 2024
2023
Hello Word! 2023
可以看到,C++ 的输入输出并没有指定变量类型,这是 C++ 的两个新特性叫 函数重载 和 运算符重载 来实现的,可以达到自动识别类型的效果。
还值得一提的是,C语言的输入输出 ( printf
、 scanf
) 通常比 C++ 的输入输出要快。这主要是因为 C++ 兼容 C 语言,C++ 在去缓冲区输入输出信息时会先检测有没有 C 语言的东西,如果有会先清空缓冲区再去输入输出信息。当然你也可以去把 C++ 的这个缓冲区检测取消掉,这个时候 C++ 的输入输出速度就提上来了。
四、缺省参数
C++ 支持缺省参数,在写缺省参数的时候需要严格按照语法来写。如果不是全缺省,缺省参数一定是在函数参数的右边的。因为我们调用函数时,函数形参会从左往右依次取值,如果第一个是缺省参数而第二个不是缺省参数,我又只传了一个参数该怎么办呢?
这时,因为 C++ 语法不支持这样做,所以这个函数参数写法是错误的。
#include <iostream>
using namespace std;
// 错误写法
void Function(int a = 1, int b, int c = 3)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
// 正确写法
void Function(int a, int b = 2, int c = 3)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
int main()
{
Function(4);
return 0;
}
缺省参数不能在函数定义和函数声明中同时给,只能在函数声明中给出。不然会出现语法错误,编译器不知道该用哪一个。
// 函数声明
void Function(int a = 1, int b = 2, int c = 3);
int main()
{
Function(4);
return 0;
}
// 函数定义
void Function(int a, int b, int c)
{
cout << a << endl;
cout << b << endl;
cout << c << endl;
}
五、函数重载
C++ 支持函数重载,函数重载是指函数名相同,但是参数类型不同。参数类型不同分为参数个数不同、类型不同、类型顺序不同。只要符合其中任意一个条件就符合函数重载。
值得一提的是返回值不同并不能构成函数重载。
函数重载的调用歧义
注意看,下面这两个函数是否满足函数重载。答案是满足,但是这两个函数在调用的时候会出现问题,如果调用这个函数的时候没有加参数那么是调用的哪一个函数呐?编译器也不知道,所以会报错函数调用出现歧义。
void Function()
{
cout <<