【穿越Effective C++】条款01:视C++为一个语言联邦

58 阅读3分钟

条款1:视C++为一个语言联邦

这个条款是Scott Meyers为我们建立的至关重要的C++世界观。它指出,C++并不是一个具有单一规则的整体语言,而是由四个主要“子语言”组成的联邦。每个子语言都有自己的惯例、编程范式和高效编程的规则。理解这一点是理解C++多重范式编程和应对其复杂性的关键。


核心思想思维导图

mindmap
  root((C++ 语言联邦))
    
    1 C
      :::style1
      1.1 基础
        : 内置类型
        : 数组/指针
        : 预处理器
        : 语句/控制流
      1.2 规则
        : 默认按值传递
        : 内置类型操作高效
    
    2 面向对象C++
      :::style2
      2.1 基础
        : 类
        : 封装
        : 继承
        : 多态
        : 虚函数
      2.2 规则
        : 按常量引用传递
        : 数据封装
        : 接口设计
    
    3 模板C++
      :::style3
      3.1 基础
        : 模板元编程
        : 编译时计算
        : 泛型编程
      3.2 规则
        : 参数推导
        : 编译期决策
        : 了解依赖名称
    
    4 STL
      :::style4
      4.1 基础
        : 容器
        : 迭代器
        : 算法
        : 函数对象
      4.2 规则
        : 按值传递迭代器
        : 遵循约定/扩展性

各联邦成员详解

1. C

  • 描述:C++的基础,包含了C语言的所有核心部分。
  • 构成:内置数据类型(int, double, char*等)、数组、指针、预处理器、语句和控制流等。
  • 高效编程守则:在这个层级,规则与C语言基本相同。例如,内置类型通过值传递通常比通过引用传递更高效,因为避免了指针间接寻址的开销。

2. 面向对象的C++

  • 描述:这是C with Classes的扩展,支持面向对象编程。
  • 构成:类、封装、继承、多态、虚函数(动态绑定)等。
  • 高效编程守则:这里的规则开始变化。由于用户自定义类型(类)的存在,const引用传递对象通常比按值传递更高效,可以避免不必要的对象构造和析构成本。此外,数据封装和接口设计变得至关重要。

3. 模板C++

  • 描述:这是C++的泛型编程部分,也是模板元编程的基础。
  • 构成:模板、模板特化、SFINAE、编译时计算等。
  • 高效编程守则:这是一个全新的世界。编程的焦点从运行时转移到了编译时。你需要理解模板参数推导、依赖名称(typename关键字的作用)、以及如何通过模板实现编译期多态。在这里,传递引用通常更受青睐,因为它能与类型无关地工作。

4. STL

  • 描述:标准模板库,一个非常特定的、基于模板的库。
  • 构成:容器(vector, map)、迭代器、算法(sort, find)和函数对象(仿函数)。
  • 高效编程守则:STL有自己的一套约定俗成的规则。例如,迭代器是按值传递的(它们被设计成轻量级的,类似于指针)。你需要遵循STL的约定来创建可与之协作的组件(比如,你的自定义迭代器必须满足特定的条件)。

关键总结与启示

  1. 从“单一规则”到“多重规则”:当你从C++的一个子语言切换到另一个时,你的高效编程策略也需要随之改变。例如,在C部分,你习惯用值传递;但在面向对象C++部分,你应该优先考虑常量引用传递。

  2. 理解而非死记:这本书后续的许多条款,都是基于这个“联邦”视图。某个条款可能只在特定的子语言下是最高效的规则,而在另一个子语言下可能不适用甚至适得其反。理解你当前代码主要属于哪个联邦,是应用这些条款的前提。

  3. 降低心理压力:这个观点有助于新手减轻对C++复杂性的恐惧。你不必一次性掌握所有规则。可以先精通其中一个子语言(如面向对象C++),然后逐步将其他子语言(如STL)的规则融入你的知识体系。

核心记忆点C++是一个多范式语言联邦。切换编程上下文时,请记得切换你的高效编程规则集。