Zhao Dongyu's Blog

A life which is unexamined is not worth living.

0%

C++Primer学习

学习C++

起源

1、之前看一个NV公司的人分享经验,就是后悔没有好好学习C++;

2、昨日,丁大佬指导我要把C++学好。

想想自己一直在吃c语言的底子,确实没有发展上限了,这二件事情的碰撞,让我燃起学习C++的热情!

理由

(引用 孟岩推荐序 2013 年 8 月)

C++11 标准公布之后,C++社群出现了久违的热情,有人甚至叫出“C++的复兴”。指望 C++回到 20 世纪 90 年代中期那样的地位显然是昧于大势的奢望,但是 C++经历了这么多年的打磨与起伏,其在工业界的地位已经非常稳固,在很多领域里已经是不可取代也没必要被取代的统治者。新标准的出现能够大大提升 C++开发的效率和质量,因此赢得欢呼也是情理之中。在这种氛围之下,编译器实现的速度也令人惊喜。短短两年时间,从开源的 GCC、LLVM 到专有的 VisualC++和 Intel C++,对于新标准的追踪之快,覆盖之全,与当年 C++98 标准颁布之后迟迟不能落地的窘境相比,可谓对比强烈。当年是热情的开发者反复敦促厂商实现完整标准而不得,为此沮丧无奈,那种心情,至今记忆犹新。时过境迁,今天是编译器实现远远冲在前面,开发者倒是大大地落在了后面。

时至今日,能够基本了解 C++11 标准的程序员恐怕不多,而能够以新的 C++风格开发实践的人更是凤毛麟角。因此,今天的 C++开发者面临的一个重要任务就是快速掌握新的 C++风格和工具。

而说到教授“正宗的”C++11 编程风格,《C++Primer(第 5 版)》如同它之前的版本一样,扮演着法定教科书的角色。

一种优秀的编程语言,一定要对于计算这件事情实现一个完整和自洽的抽象。十几年来编程语言领域的竞争,除却实现质量之外,基本上是在比拼抽象的设计。而 C 语言之所以四十年长盛不衰,根本在于它对于现代计算机提供了一个最底层的高级抽象:凡是比它低的抽象都过于简陋,凡是比它高的抽象都可以用 C 语言构造出来。C++成功的根本原因,恰恰是因为它虽然试图提供一些高级的抽象机制,但是其根基与 C 在同一层面。正因为如此,每当你需要走下去直接与硬件对话时,C++成为 C 之外唯一有效率的选择。我的一个朋友在进行了多年的大型系统软件开发之后,不无感慨地说,C++最大的力量不在于其抽象,恰恰在于其不抽象。

话虽然如此,但是 C++之所以脱离 C 而存在,毕竟还是因为其强大的抽象能力。BjarneStroustrup 曾经总结说,C++同时支持 4 种不同的编程风格:C 风格、基于对象、面向对象和泛型。事实上,把微软的 COM 也算进来的话,还可以加上一种“基于组件”的风格。这么多的风格共存于一种语言,就是其强大抽象机制的证明。但是,在 C++11 以前,C++的抽象可以说存在若干缺陷,其中最严重的是缺少自动内存管理和对象级别的消息发送机制。今天看来,C++98 只能说是特定历史条件造成的半成品,无论是从语言机制,还是标准库完备程度来说,可以说都存在明显的、不容忽略的缺陷。其直接后果,就是优雅性的缺失和效率的降低。我本人在十年前曾经与当时中国 C++社群中不少杰出的人物交流探讨,试图从 C++98 中剪裁出一个小巧、优雅的、自成一体的子集,希望至少在日常编程中,能够在这个子集之内可以写出与当时的 Java 和 C#同样干净明晰的代码。为此我们尝试了各种古怪的模板技巧,并且到处寻找有启发的代码和经验来构造这个语言子集,结果并不理想,甚至可以说是令人非常失望。后来我在我的博客中发表过好几篇文章,探讨所谓的 C++风格问题,其实就是说,C++不支持简洁明快的面向对象风格,大家还不如回到基于对象甚至 C 语言的风格,最多加点模板,省一点代码量。非要面向对象的话,就必须依赖像 Qt 或者 MFC 那样的基础设施才可以。

C++11 出来之后,增强的语言机制和大为完善的标准库,为 C++语言的编程风格带来了革命性的变化。如果能够纯熟地运用 C++11 的新特征、新机制,那么就能够形成一种简洁优雅的 C++编程风格,以比从前更高的效率、更好的质量进行软件开发。对于这种新的风格,我认为“直觉、自然”是最佳的描述。也就是说,解决任何问题不必拘泥于什么笼盖一切的编程思想,也不再沉溺于各种古怪的模板技巧中无法自拔,而是能够根据那个问题本身采用最自然、最符合直觉的方式。C++有自己的一套思维方式,比如容器、算法、作为概念抽象的对象等,很大程度上这套思维方式确实是合乎直觉的。只有到了 C++11 这一代,C++语言的高级抽象才基本完备,这样一种风格才可能真正落实。因此可以说 C++11 对于 C++98 而言,不是一次简单的升级,而是一次本质的跃升。

学习新的 C++风格,并不是轻而易举的事情。即便对于以前已经精通 C++的人来说,熟练掌握 rvaluereference、move 语义,了解 unique_ptr、shared_ptr 和 weak_ptr 的完整用法,明智地使用 function/bind 和 lambda 机制,学习 C++Concurrency 的新技术,都绝非一朝一夕之功。对于那些初学者来说,这件事情更不简单。

本书无论对于初学者还是提高者,都是最经典的教科全书。一直以来,它的特点就是完整而详细,基本上关于语言本身的问题,都可以在这本书里得到解决。而本书的另一个重要优点,就是其完全基于新的编程风格编写,所有的例子和讲解都遵循 C++11 标准所体现出来的思路和风格进行,如果能够踏下心来认真学习和练习,那么就能“一次到位”地掌握 C++11,尽管可能会比较慢。有经验的 C++开发者阅读这本书当然不用从头到尾,选择自己关心的内容学习 C++11 的新特性就可以,是快速升级自身能力的捷径。

差不多十年前,我提出一个观点,每一个具体的技术领域,只需要读四五本书就够了。以前的 C++是个例外,因为语言设计有缺陷,所以要读很多书才知道如何绕过缺陷。现在的 C++11 完全可以了,大家读四五本书就可以达到合格的水平,这恰恰是语言进步的体现。

本书是这四五本中的一本,而且是“教程+参考书”,扛梁之作,初学者的不二法门。另一本是《C++标准程序库(第 2 版)》,对于 C++熟手来说更为快捷。ScottMeyers 的 Effective C++永远是学习 C++者必读的,只不过这本书的第 4 版不知道什么时候出来。AnthonyWilliams 的 C++ Concurrency inAction 是学习用标准 C++开发并发程序的最佳选择。国内的作品,我则高度推荐陈硕的《Linux 多线程服务端编程》。这本书的名字赶跑了不少潜在的读者,所以我要特别说明一下。这本书是 C++开发的高水平作品,与其说是教你怎么用 C++写服务端开发,不如说是教你如何以服务端开发为例子提升 C++开发水平。前面几本书都是谈标准 C++自己的事情,碰到像 iostream 这样失败的标准组件也不得不硬着头皮介绍。而这本书是接地气的实践结晶,告诉你面对具体问题时应怎样权衡,C++里什么好用,什么不好用,为什么,等等。

今天的 C++学习者是非常幸运的,可以在 C++11 这个基础上大步向前,不必再因为那些语言的缺陷和过度的技巧而烦恼。大家静下心来认真读几本书,可以打下很好的基础。

记录

注释

Although the compiler ignores comments, readers of our code do not. Programmers tend to believe comments even when other parts of the system documentation are out of date. An incorrect comment is worse than no comment at all because it may mislead the reader. When you change your code, be sure to update the comments, too!

虽然编译器会忽略注释,但我们代码的读者不会。即使系统文档的其他部分已经过时,程序员也倾向于相信注释。不正确的注释比没有注释更糟糕 因为它可能会误导读者。当您更改代码时,请务必更新注释!

Comment pairs generally are used for multiline explanations, whereas double-slash comments tend to be used for half-line and single-line remarks

注释对通常用于多行解释,而双斜线注释往往用于半行和单行注释

debug

It is a good practice to correct errors in the sequence they are reported. Often a single error can have a cascading effect and cause a compiler to report more errors than actually are present.

It is also a good idea to recompile the code after each fix—or after making at most a small number of obvious fixes. This cycle is known as edit-compile-debug.

按照错误报告的顺序来纠正错误是一种很好的做法。通常,一个错误会产生连锁反应,导致编译器报告的错误比实际存在的错误更多。每次修复后重新编译代码也是一个好主意——或者在进行少数明显的修复后重新编译代码。这个循环称为编辑-编译-调试

Class

In C++ we define our own data structures by defining a class. A class defines a type along with a collection of operations that are related to that type. The class mechanism is one of the most important features in C++. In fact, a primary focus of the design of C++ is to make it possible to define class types that behave as naturally as the built-in types.

在 C++ 中,我们通过定义类来定义自己的数据结构。一个类定义了一种类型,以及与该类型相关的操作集合。类机制是 C++ 中最重要的特性之一。事实上,C++ 设计的主要重点是使定义行为与内置类型一样自然的类类型成为可能

Perhaps the most important feature in C++ is the class, which lets programmers define their own types. In C++ such types are sometimes called “class types” to distinguish them from the types that are built into the language.

Some languages let programmers define types that specify only what data make up the type. Others, like C++, allow programmers to define types that include operations as well as data.

A major design goal of C++ is to let programmers define their own types that are as easy to use as the built-in types. The Standard C++ library uses these features to implement a rich library of class types and associated functions.


我的疑问:C++里面的类和结构体有什么区别?

在 C++ 中,类(class)结构体(struct) 的基本功能几乎是相同的,它们都可以用来定义数据成员和成员函数,具有相似的语法和行为。然而,二者之间的主要区别在于默认的访问权限以及在代码设计上的一些常见约定:

1. 默认访问权限

  • 类(class):默认情况下,类的成员是 私有(private) 的。即,所有未指定访问权限的成员在类中都是私有的。
  • 结构体(struct):结构体的成员默认是 公有(public) 的。也就是说,如果不显式定义访问修饰符,所有成员在结构体中都是公有的。

示例

1
2
3
4
5
6
7
8
9
10
class MyClass {
int x; // 默认是 private
public:
int y;
};

struct MyStruct {
int x; // 默认是 public
int y;
};

2. 代码风格和用途上的习惯

  • :在 C++ 中,类通常用于表示带有封装性和私有成员的复杂数据类型,适合用来定义对象和数据抽象。
  • 结构体:虽然 C++ 的结构体具备和类相同的功能,但通常用于表示简单的数据结构,主要用于存储数据。结构体在 C++ 中常用于兼容 C 语言的代码,也更倾向于用于无复杂行为的简单数据封装。

3. 继承时的默认访问控制

  • 类继承:当一个类从另一个类继承时,如果没有指定继承方式,则默认是 私有继承
  • 结构体继承:当结构体继承另一个结构体或类时,默认是 公有继承

示例

1
2
3
4
5
class BaseClass {};
struct BaseStruct {};

class DerivedClass : BaseClass {}; // 默认 private 继承
struct DerivedStruct : BaseStruct {}; // 默认 public 继承

4. 兼容性

  • 结构体:更接近 C 语言中的 struct,适合与 C 语言代码兼容。
  • :C++ 中独有,包含更多的面向对象特性。

5. 代码可读性和设计意图

  • 使用 class 表示对象的设计更符合面向对象编程的设计习惯,意图更加明确。
  • 使用 struct 则更适合简单的数据集合,传达出“主要用于数据存储”的意图。

总结

尽管类和结构体在 C++ 中功能相似,但类更常用于封装复杂行为和数据,而结构体更偏向简单数据存储。它们之间的区别主要在于访问控制上的默认值以及编程习惯。


In general, the class author determines all the operations that can be used on objects of the class type.

include

Headers from the standard library are enclosed in angle brackets (< >).

Those that are not part of the library are enclosed in double quotes (" ").

  • <>:用于包含标准库和第三方库的头文件,编译器直接从系统路径中查找。
  • "":用于包含用户定义的头文件,编译器优先在当前目录查找,找不到时再去系统路径查找。

constexpr

Variables declared as constexpr are implicitly const and must be initialized by constant expressions:

声明为 constexpr 的变量一定是一个常量,并且必须用常量表达式初始化

  • 常量类型:const 常量的值可以在运行时确定,constexpr 要求值在编译时确定。
  • 应用范围:constexpr 可以用于函数,以便让编译器在编译时计算结果,而 const 不具备此功能。
  • 性能:constexpr 能提升编译时计算的性能,而 const 可能会产生运行时开销。
Thanks for your support.