1. 译序
C++是一个难学易用的语言。
C++的难学,体现在广博的语法,背后的语义;语义背后的深层思维;深层思维背后的对象模型。
C++四种不同而又相辅相成的编程泛型:基于过程型,基于对象型,面向对象型,一般模型。
衍生的复合术语:base class,derived class,super class,subclass,class templates等。
object和type,中译词“对象”和“类型”。更贴切的是“物件”和“型别”。
2. 导读部分
本书的目的是探讨如何有效运用C++。书中提出的忠告有两类:一般性的设计策略和带有具体细节的特定语言特性。
设计上的讨论大多是选择题,不同做法完成同一件工作的情况下,选择:
inheritance(继承)还是templates(模板)。
public继承还是private继承。
private继承还是composition(复合)。
member函数还是non_member函数。
pass_by_value还是pass_by_reference。
3. 条款一:让C++成为一个语言联邦
C++发展与C with class,但拥有不同于C with class的观念,特性和编程战略,比如Exceptions,templates,STL等。
C++多重范型编程语言:过程型(procedural)面向对象型(object-oriented)函数型(functional)泛型(generic)元编程型(metaprogramming)。
C++能力强大,弹性十足,但所有适当的方法都有例外,合理运用这些强大的特性,方法是将C++视为由相关语言组成的联邦。
C++语言主要的次语言:
C:C++有时解决问题的方式是高级的C语言,但是C缺乏高级特性。
Object-Oriented C++:这部分是C with class的诉求。classes(构造析构)encapsulation(封装)inheriance(继承)polgmorphism(多态)virtual函数(动态绑定)
Template C++:C++泛型编程部分,template威力强大,能带来崭新的编程范式,TMP:模板元编程。
STL:STL是template程序库,它对容器(containers)迭代器(iterators)算法(algorithms)以及函数对象(function-objects)的规约有很强的紧密配合与协调。
准则:
C-like(内置类型)而言:pass_by_value 比 pass_by_reference高级。
C part of C++移往Object-Oriented C++,由于构造和析构存在,pass_by_reference_to_const往往更好。
Template C++尤其如此。
STL中,迭代器和函数对象都在C指针上构造的,旧式的C pass_by_value再次适用。
4. 条款二:尽量以const eunm inline 替换 #define
#define 不被视为语言的一部分。define的名称不在符号表中,由于define定义值引发的问题将很难定位。
常量替代宏 const double ASP = 1.653;
两种特殊的情况:①定义常量指针,有必要把指针也声明为cosnt。②class专属常量,需要声明为静态成员。作用域也限定在了class中。
#define无法创建一个class专属常量,#define并不重视作用域。
旧式编译器可能不允许在其声明式上获得初值,替代方法是“the enum hack”。
取代宏函数的方案:template inline函数。
单纯常量,以const对象或者enum替换#define。
形似函数的宏,改用inline函数替代#define。
5. 条款三:尽可能使用const
const语法变化多端,但是并不高深莫测。const在星号左边,被指物是常量。const在星号右边,指针自身是常量。
const出现在类型名的两侧时,效果是一样的。
STL迭代器和const:STL迭代器是以指针为根据塑模出来的,迭代器等同于T*。
const面向函数声明时的应用:const与返回值,参数,函数自身(成员函数)关联。
返回值是const:函数返回值不期望被修改时使用,多用于左值的运算符重载,例如 * 的重载。这种情况下参考基础类型在相同情况的的表现。
const成员函数:
const成员函数的目的是确认该函数可用于const对象上。
可以知道哪个函数可以修改对象的内容,而哪些不行。
使操作cosnt对象称为可能。
两个成员函数只是常量性不同,可以被重载,const是函数签名的一部分。
实际程序中,const对象大多用于passed by pointer_to_const 或者 passed by reference_to_const的传递结果。
成员函数时const,分为两种概念行为,bitwise constness 和 logical constness
bitwise const 认为成员函数不修改任何成员变量时,才能说是const,符合C++对常量性的定义。const成员函数不能修改任何non-static成员变量。
很多函数不十足具备bitwise const特性,却能通过bitwise测试,例如函数返回指针成员所指向的内容,在函数外部可以修改成员值。
以上的情况导出了logical constness,const成员函数可以修改它所处理的对象内部某些bit,但是只有在客户端监测不到时才能如此。
对象有在const成员函数中修改no-static成员的需求,C++引入了mutable,释放了no-staic成员变量的bitwise constness 约束。
在const和non-const成员函数中避免重复
当成员函数需要const版本和非const版本时,使用const版本实现non-const版本。
步骤:实现const版本;返回类型为const引用;函数类型是const。实现non-const版本;使用static_cast把*this转为const;访问成员;对成员类型进行const_cast,去const属性。
反向的const调用non-const模板是错误的,违反了const的本质属性。
6. 条款四:确定对象被使用前已经被初始化
赋值和初始化的区别:构造函数内部都叫赋值,在初始化列表中的行为叫初始化。
C++有固定的成员函数初始化次序。base class 早于 derived classes。成员的初始化列表按声明次序初始化。
non-local static对象初始化次序:
函数内部的static对象时local static,其余的static对象都是non-local static。
两个non-local static 互相依赖(处于不同的编译单元),两个对象的初始化次序没有明确的定义。
解决这类情况的方式是把static对象放在static函数中定义返回。