欢迎来到Harper·Lee的学习笔记!
博主主页传送门:Harper·Lee的博客主页!
想要一起进步的uu来后台哦!
在此之前,我们所学习的C语言是一种结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机, 20世纪80年代, 计算机界提出了面向对象思想(OOP,即object oriented programming),支持面向对象的程序设计语言应运而生。
1982年,本贾尼·斯特劳斯特卢普(Bjarne Stroustrup)博士在C语言的基础上引入并扩充了面向对象的概念,发明了一种新的程序语言。为了表达该语言与C语言的渊源关系,命名为C++。因此: C++是基于C语言而产生的,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计。
1979年,贝尔实验室的本贾尼等人试图分析unix内核的时候,试图将内核模块化,于是在C语言的基础上进行扩展,增加了类的机制,完成了一个可以运行的预处理程序,称之为 C with classes。C++的发展主要经历了以下几个阶段:
| 阶段 | 发展内容 |
|---|---|
| C with classes | 类及派生类、公有和私有成员、类的构造和析构、友元、内联函数、赋值运算符重载等 |
| C++1.0 | 添加虚函数概念,函数和运算符重载,引用、常量等 |
| C++2.0 | 更加完善支持面向对象,新增保护成员、多重继承、对象的初始化、抽象类、静态成员以及const成员函数 |
| C++3.0 | 进一步完善,引入模板,解决多重继承产生的二义性问题和相应构造和析构的处理 |
| C++98 | C++标准第一个版本,绝大多数编译器都支持,得到了国际标准化组织(ISO)和美国标准化协会认可,以模板方式重写C++标准库,引入了STL(标准模板库) |
| C++03 | C++标准第二个版本,语言特性无大改变,主要:修订错误、减少多异性 |
| C++05 | C++标准委员会发布了一份计数报告(Technical Report,TR1),正式更名C++0x,即:计划在本世纪第一个10年的某个时间发布 |
| C++11 | 增加了许多特性,使得C++更像一种新语言,比如:正则表达式、基于范围for循环、auto关键字、新容器、列表初始化、标准线程库等 |
| C++14 | 对C++11的扩展,主要是修复C++11中漏洞以及改进,比如:泛型的lambda表达式,auto的返回值类型推导,二进制字面常量等 |
| C++17 | 在C++11上做了一些小幅改进,增加了19个新特性,比如:static_assert()的文本信息可选,Fold表达式用于可变的模板,if和switch语句中的初始化器等 |
| C++20 | 自C++11以来最大的发行版,引入了许多新的特性,比如:模块(Modules)、协程(Coroutines)、范围(Ranges)、概念(Constraints)等重大特性,还有对已有特性的更新:比如Lambda支持模板、范围for支持初始化等 |
| C++23 | 制定ing(中间出现一些小插曲) |
| C++26 | …… |
时间轴如下:
虽然C++技术不断地在发展,但是目前大多数的公司使用的是C++98和C++11标准。

根据上图最新的TIOBE调查结果可知,C++、C、python都是比较热门的编程语言,发展前景比较好,因此就业前景相对广阔,一些自然也相对卷一些。在未来我们至少需要学习两门以上的编程语言,因此,不要走马观花的学习,而是要精益求精,实质性的精通掌握一两门语言。这样,上手其他语言时也会比较的得心应手。
注意:排名不能说明哪个语言好,哪个不好,每门编程语言都有适应自己的应用场景。
C++的应用领域比较广阔,主要包括以下几个领域:
校招都是公司需要什么技能自己就学习什么技能的,因此要学会包装自己,有方向地调衡自己。
学习C++: { int a = 0; double b = 3.0; char c = 'x'; cout << "Harper·Lee" << endl; //cout:标准输出对象(控制台) // << :流插入运算符;>>:流提取运算符 //endl:end line,相当于换行符 std::cout << a << endl;//因为上面已经展开了,就不需要指定了 cout << a << " " << b << endl; //可以自动识别变量的类型 cin >> a; cin >> b >> c; cout << a << endl; cout << &a << endl; cout << b << " " << c << endl; //cin:标准输入对象(键盘) return 0; } 运行结果:
、
#include using namespace std; int main() { // 在io需求⽐较⾼的地⽅,如部分⼤量输⼊的竞赛题中,加上以下3⾏代码 // 可以提⾼C++IO效率 ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); return 0; } https://legacy.cplusplus.com/reference/?(非C++官方文档)
https://zh.cppreference.com/w/cpp?(中文版)
https://en.cppreference.com/w/?(英文官方版)
书籍参考:C++Primer(作为语法字典) / Effective C++侯捷(应用经验和坑) / STL源码剖析(库底层、中后期)。
C++学起来很难是必然的,因为就语法而言,C++要解决C语言的一些问题,也要追求效率,此外历史发展比较早,发展历程总会有些许坎坷。
请注意:
//test.cpp #include int a = 10;//全局变量 int main() { int a = 5; printf("%d\n", a); //通过局部域作用限定符访问指定命名空间的变量 printf("%d\n",::a);//::符号前面是空白(有无空格都一样),默认代表访问的是全局域 return 0; } 
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
有如下的代码:
#include #include int rand = 10; int main() { printf("%d\n", rand); return 0; }//我们定义的变量名和库里面的名称冲突了 报错:
首先我们分析一下为什么会有这样的错误:
报错原因: 编译报错:error C2365: “rand”: 重定义;以前的定义是“函数”。rand在cpp文件里面是定义的一个变量,但是rand在stdlib库中代表一个函数,就出现了重定义的情况,在这里就叫做命名冲突。(注意:rand作为函数时,函数名默认是函数的地址。)
解决方法:这种情况在C语言中可以通过重新修改变量的名字,使其不再与关键字或者函数名重名即可;在c++中,可以通过命名空间解决。
#include #include #include namespace Harper//定义了一个命名空间域 { int rand = 10;//在bit命名空间里面,rand仍然是全局变量 } void func() { printf("%p\n", rand);//访问的是函数指针,函数名默认是函数的地址,%d改成%p printf("%d\n",Harper::rand);//打印访问Harper命名空间中变量rand的值 } int main() { func(); return 0; } 运行结果:
namespace关键字定义全局命名空间域,后面跟命名空间的名字,然后接⼀对 {} 即可,{}中即为命名空间的成员。
#include #include namespace Harper { int year = 19; } int main() { printf("%d\n", Harper::year); return 0; } 运行结果:
#include #include namespace Harper { // 命名空间中可以定义变量/函数/类型 int rand = 10; int Add(int left, int right) { return left + right; } struct Node { struct Node* next; int val; }; } int main() { //函数调用 printf("%d\n", Harper::Add(1, 1)); //结构体 struct Harper::Node p1;//而不是Harper:: struct Node p1; //因为对象是Node,struct是关键字 return 0; } namespace只能定义在全局,但是它可以嵌套定义。就像多个项目组里会定义出一样的名称,可以通过namespace解决;但如果在一个项目组即同一个命名空间里面,各个分工合并代码时就出现冲突了,这样就可以通过在同一个命名空间里嵌套再次定义命名空间。
#include #include namespace Harper { namespace Lee { int rand = 10; int Add(int left, int right) { return left + right; } } namespace Aururo { int Sub(int left, int right) { return left * right; } } } int main() { printf("%d\n", Harper::Lee::Add(1, 1)); printf("%d\n", Harper::Aururo::Sub(2, 3)); return 0; } 运行结果:
#include #include namespace Harper { int rand = 5; } namespace Harper { int ret = 1; } int main() { printf("%d\n", Harper::rand + Harper::ret); return 0; }//文件中的同理 运行结果:
编译查找⼀个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间⾥⾯去查找。因此我我们可以通过三三种方式访问命名空间。
指定命名空间访问,项目中比较推荐这种方式。
#include #include namespace Harper { int rand = 10; } void func() { printf("%d\n", Harper::rand); } 使用using展开命名空间中某个频繁使用的成员,项目中经常访问的不存在冲突的成员可使用此法。
#include #include namespace Harper { int year = 19; int a = 6; } using Harper::a;//展开常用的a int main() { printf("%d\n", Harper::a); return 0; } 使用using namespace展开整个命名空间,在项目中并不推荐,冲突的风险很大,可在日常的小练习中使用全部展开,将这个繁琐的指定命名空间过程化简。
#include #include //展开整个命名空间 namespace Harper { int year = 19; } using namespace Harper; int main() { printf("%d\n", Harper::year); return 0; } 注意:
喜欢的uu记得三连支持一下哦!