转眼间, 就进入C++这个新的篇章啦!
我带着些许心悸 和 激动:
心悸的是, 时间过的是如此之快, 上个学期咋们还在一起谈着C语言, 数据结构, 现在又要一起学习C++啦; 心悸的是, 我在上个半年, 耽误了很多时间, 遗漏了许多博客没写。。。
激动的是, 我们终于要爽起来了, 相信我们在学习C++之后, 尤其是学习了C++的STL, 模板之后, 就不想写C语言了(当然, C语言也有自己的优势哎)
C++是在C语言的基础之上, 容纳进去了面向对象编程思想, 并增加了许多有用的库, 以及编程范式等等。
接下来, 我们初识C++(主要是C++98)章节的主要任务是:
了解C语言语法的不足, 以及C++是如何对C语言设计不合理的地方进行优化的
为后续的类和对象学习打基础
🫅1. C++关键字
C++ 总共有63 个 关键字, C语言有32个关键字。 在这个阶段, 我们对关键字只是起着了解作用, 以后碰到会进行详解的。
🫅 2.命名空间
应该不少萌新有些疑问: 啥是命名空间? 命名空间有啥用? 初学者有些疑问是一件好事, 我们可以带着疑问, 去有重点地学习。
让我们先来看看下面的一串代码:
#include<stdio.h> int size = 4; int size = 5; int main() { printf("%d\n", size); return 0; } ***** error : size 重定义 ******
看到上面的代码, 有人就会说: 老陈, 你怎么写出这么挫的代码? 怎么定义了 size 两次?
嘿嘿一笑😀😀, 这么写有它的实际意义啊:你想啊, 你以后参加工作, 肯定是分项目给你和你的同事做啊, 最后把你们的代码合并起来。 如果最后你的代码中的变量名 和 张三的变量名 冲突了?怎么办?打一架、、、😀😀
这时候, 我们的祖师爷 - 本贾尼就想出了一个办法:能不能在每个人的代码之间起一堵 “墙” , 你的变量和函数 在你的区域内部起作用, 出了你的区域就不会起作用了。
这一堵墙的专业名词 就叫做 命名空间
在C/C++中, 变量、函数 和 后面要学的类都是大量存在的, 这些变量、 函数 和 类的名称都存在于全局作用域中, 可能会导致许多冲突。 使用命名空间的目的是 对标识符的名称进行本地化, 以避免命名冲突 或 名字污染, namespace关键字的出现就是针对这种问题的
那么问题来了: 这个namespace 是怎么用的?
🤷♂️2.1命名空间的定义
// 1.命名空间内可以定义变量, 函数, 类型 namespace mu { int rand = 5; int Sub(int a, int b) { return a - b; } } // 2.命名空间可以嵌套 namespace N1 { int a; int b; struct SLTNode { int val; struct SLTNode* next; }; namespace N2 { int a; int b; struct SLTNode { int val; struct SLTNode* next; }; } } // 3.同一个工程中允许多个相同的命名空间, 编译器最终会合并成一个命名空间中 // eg: 如果一个工程中, 存在着 test.cpp , CSDN.cpp 两个文件, // 这两个文件都存在着 N1 这个命名空间, 最终会合并成一个N1的命名空间
总结:
1.命名空间的构成: 关键字 namespace, 命名空间名(自己定), {}(注意跟结构体区分开, 后面没有 逗号 ;)
2.一个命名空间就定义了一个新的作用域(但是这个不影响生命周期),命名空间内的内容都局限于改命名空间中
3.命名空间的作用: 解决全局的命名冲突问题
这里有人就会十万个为什么: 为什么不解决局限的命名冲突问题啊?
首先, 我们都知道局部变量是不能重定义的, 它重定义 一是 语法问题, 二是 没啥用。
其次, 我们应该明确,我们现在学的知识是为了后面的类、 对象学习打基础。 这些玩意都是存在于全局作用域中的, 解决的是他们的命名冲突问题
🤷♂️2.2命名空间的使用
学到这里, 有些人又有些疑问: 老陈, 我把我写的代码用命名空间包了起来, 那我们在工程中又怎么使用自己写的代码??
好问题! 这就是我们即将要讲的命名空间的使用。
系好安全带, 我们发车了!!🤞🤞
我们先了解一下编译器对域(墙)的搜索顺序:
那我们如何突破局部域 和 全局域 , 从而访问到我们的命名空间域呢??
一共有三种方式:
1.用作用域限定符(::)去访问
namespace N { int a = 10; int b = 8; struct SLTNode { int val; struct SLTNode* next; }; } int main() { printf("%d\n", N::a); return 0; }
2.使用 using 展开某命名空间的成员
namespace N { int a = 10; int b = 8; struct SLTNode { int val; struct SLTNode* next; }; } using N::b; int main() { printf("%d\n", b); return 0; }
3.使用using namespace 展开某个命名空间域
namespace N { int a = 10; int b = 8; struct SLTNode { int val; struct SLTNode* next; }; } using namespace N; int main() { printf("%d\n", a); printf("%d\n", b); return 0; }
总结一下上面的几种情形:
🫅 3.C++输入 & 输出
有些老铁, 到了这里就想问: 老陈, 我们搞了这么多东西, 还不知道 C++ 是如何输入 和 输出的?你这搞得不行啊, 赶快来讲一讲!!
由于C++ 兼容 C语言, 那么scanf 和 printf 还是照常能用的, 不过需要引用 头文件 cstdio , 不过好像在最新的C++语法里, 引用头文件 iostream 就能照用 这两个函数 。
#include<iostream> // #include<cstdio> int main() { int a = 0; scanf("%d", &a); printf("%d\n", a); return 0; } ***** 5 5 *****
有些老铁又要问了: 那C++有么有自己专用的输入 和 输出 函数啊?cin 和 cout 就是你们要的答案
先别发问, 我先给你们看一下例子:
#include<iostream> using namespace std; int main() { int n; cin >> n; cout << n << endl; return 0; } ***** 5 5 *****
说明:
1.使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件以及按命名空间使用方法使用std。
2.cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含< iostream >头文件中。
3.<< 是流插入运算符,>> 是流提取运算符。
4.使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。C++的输入输出可以自动识别变量类型。
5.实际上cout和cin分别是ostream和istream类型的对象,>>和<<也涉及运算符重载等知识,这些知识我们我们后续才会学习,所以我们这里只是简单学习他们的使用。后面我们还有有一个章节更深入的学习IO流用法及原理。
注意:早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文件不带.h;旧编译器(vc 6.0)中还支持<iostream.h>格式,后续编译器已不支持,因此推荐使用+std的方式。
🐉🐉🐉🐉🐉
std是C++标准库的命名空间,如何展开std使用更合理呢?
1.在日常练习中,建议直接using namespace std即可,这样就很方便。
2.using namespace std展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对象/函数,就存在冲突问题。该问题在日常练习中很少出现,但是项目开发中代码较多、规模大,就很容易出现。所以建议在项目开发中使用,像std::cout这样使用时指定命名空间 + using std::cout展开常用的库对象/类型等方式。
自是汝才难用世,岂真吾相不当侯?
须知少日拏云志,曾许人间第一流