《Effective C++》(1-4)
条款01:视C++为一个语言联邦
Q. C++联邦由哪些次语言构成?
C:基础语法
面向对象:类、封装、继承、多态、虚函数等
模板:泛型编程和模板元编程(TMP)
STL:标准模板库,包含容器、迭代器、算法和函数对象的设计模式
Q. 为什么要视为语言联邦?
为了不同的子语言使用不同的编程习惯。
条款02:尽量以 const、enum、inline 替换 #define
补充:C11 之后 constexpr 更加强化了这一思想
Q. 为什么不建议在 C++ 中使用 #define 定义常量?
#define不做类型检查,宏展开可能导致难以发现的错误。而const、enum、inline 是类型安全的。
预处理后,代码中所有 宏名 都变成了 值 ,符号表没有宏名,调试器只会看到常量值,看不到宏名,调试时遇到报错只看到值很难定位。
Q. 推荐做法
- enum是编译期常量不占内存(编译期常量在编译阶段就已知具体数值,编译器会把它直接写到指令中(代码段),不用再存内存变量; 而运行期常量,必须在运行时算出来并存到数据段)
- 宏函数应全部替换为
inline或constexpr函数。 - 常量应首选
constexpr(支持编译期计算)或inline constexpr(跨文件共享) - 宏定义的最佳实践是只在条件编译、平台特定代码中用宏(如
#ifdef _WIN32)
条款03:尽可能使用 const
补充:C11 之后还可以结合 constexpr
Q. const 可以修饰哪些东西?为什么要“尽可能使用它”?
使用理由:
-
防止无意修改数据
-
增加可读性(一眼能看出这个变量是只读的)
-
编译器优化(某些情况下可生成更高效代码)
适用范围:
- 变量
- const int a = 10; // 常量
- 指针
- 常量指针:int* const p; //(p 不能改指向,但能改它指的值)
- 指针常量:const int* p; // 指向常量的指针(不能通过 p 改值)
- 指向常量的常量指针:const int* const p; //(指向和值都不能改)
- 函数参数
-
void func(const std::string& s); // 保证函数内部不会修改 s
-
- 函数返回值
-
const std::string getName(); // 返回值不能作为左值修改
-
- 成员函数
-
class A { public: int get() const; // 承诺不修改成员变量,对象调用
const成员函数时,编译器会把 this 指针的类型改为const A*};
-
总体趋势:const 依然是基础工具,但现代C++更鼓励在编译期可知的值上用 constexpr(C11)/consteval(C20)。
条款 04:确保对象在使用前被初始化
Q. C++ 中哪些变量如果你不手动初始化,它们的值是不确定的?
Q. 成员变量为什么要放在构造函数成员初始化列表里初始化,而不是在构造函数体内赋值?
初始化列表是在对象构造时直接初始化成员,而不是先默认构造再赋值。
Q. 静态对象(static 变量)什么时候初始化?如何确保它们按正确顺序初始化?

浙公网安备 33010602011771号