天天看点

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”。

取代宏函数的方案: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函数中定义返回。

继续阅读