Effective C++ Part1

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”。
class GamePlayer {
private:
    eunm {NumTurns = 5};  
};
// enum hack在某些行为上像define,无法获得地址。
// enum hack是模板元编程的基础技术。
  • 取代宏函数的方案:template inline函数。
template <typename T>
inline void callWithMax(const T& a, const T& b)
{
    f ( a > b ? a : b );
}
  • 单纯常量,以const对象或者enum替换#define。
  • 形似函数的宏,改用inline函数替代#define。

 

5. 条款三:尽可能使用const

  • const语法变化多端,但是并不高深莫测。const在星号左边,被指物是常量。const在星号右边,指针自身是常量。
  • const出现在类型名的两侧时,效果是一样的。
  • STL迭代器和const:STL迭代器是以指针为根据塑模出来的,迭代器等同于T*。
const std::vector<int>::iterator iter = vec.begin();
// iter 作用是T* const, iter++ 是不允许的,*iter = 10;是允许的。
std::vector<int>::const_iterator cIter = vec.begin();
// iter 作用是const T*,*cIter = 10; 是不允许的,++cIter;是允许的。
  • 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函数中定义返回。
FileSystem & tfs
{
    static FileSystem fs;
    return fs;
}

 

上一篇:直播带货平台源码自定义view之利用PathEffect实现动态效果实现


下一篇:moveTo( )方法