《Effective C++》第三版-1. 让本身风俗C++(Accustoming Yourself to C++
目录[*]条款01:视C++为一个语言联邦(View C++ as a federation of languages)
[*]条款02:只管以const、enum、inline替换#define(Prefer consts, enums, and inlines to #define)
[*]替换原因
[*]两种特殊常量
[*]形似函数的宏
[*]条款03:尽可能使用const(Use const whenever possible)
[*]const和指针
[*]const成员函数
[*]在const和non-const成员函数中避免重复
[*]条款04:确定对象被使用前已先被初始化(Make sure that objects are initialized before they’re used)
[*]成员初值列
[*]成员初始化的序次
条款01:视C++为一个语言联邦(View C++ as a federation of languages)
C++有4个主要的次语言(sublanguage):
[*]C。包含区块(blocks)、语句(statements)、预处理器(preprocessor)、内置数据范例(built-in data)、数组(arrays)、指针(pointers)等;没有模板(templates)、异常(exceptions)、继承(inheritance)。
[*]Object-Oriented C++。这是C with classes部分,包含classes(包罗构造函数和析构函数)、封装(encapsulation)、继承(inheritance)、多态(polymorphism)、virtual函数等。
[*]Template C++。这是C++泛型编程(generic programming)部分。
[*]STL。涉及容器(containers)、迭代器(iterators)、算法(algorithms)、函数对象(function objects)。
Tips:
[*]C++高效编程守则视情况而变革,和使用的次语言种类有关
条款02:只管以const、enum、inline替换#define(Prefer consts, enums, and inlines to #define)
该条款可表达为:宁可以编译器替换预处理器
替换原因
#define ASPECT_RATIO 1.653
const double AspectRatio = 1.653;//以常量替换宏替换原因:
[*]暗号名称ASPECT_RATIO可能在编译器开始处理源码之前被预处理器移走,而未被编译器看到,没有进入暗号表(symbol table),故在编译错误涉及该常量时难以确定1.653的泉源。使用语言常量AspectRation则不会有这个问题。
[*]对浮点常量(floating point constant,如本例),使用常量可能比使用#define导致更少量的码,因为预处理器盲目标将宏名称替换为1.653可能导致目标码(object code)出现多份1.653,改用常量AspectRatio则不会有此问题
两种特殊常量
常量指针(constant pointers):常量定义式常位于头文件,故有必要将指针声明为const
const char* const authorName = "Scott Meyers";
const std::string authorName("Scott Meyers");//使用string更合适class专属常量:为了将常量作用于(scope)限制在class内,需要让其成为class的一个成员(member);为了确保此常量至多只有一份实体,需要让其成为static成员
class GamePlayer {
private:
static const int NumTurns = 5;//常量声明式
int scores;//使用该常量
...
};当某个东西是class专属常量+static+整数范例(integral type,如ints、chars、bools),只要不取地址,则可是有声明式而无定义式,否则需要提供定义式。
//应放入实现文件而非头文件
const int Gameplayer::NumTurns;//NumTurns的定义,声明时设定了初值故此处可不设定值旧编译器可能不允许static成员在声明式上获得初值,此时可将初值放在定义式。
class CostEstimate {
private:
static const double FudgeFactor;//static class常量声明,位于头文件
};
const double CostEstimate::FudgeFactor = 1.35;//static class常量定义,位于实现文件若译器不允许static成员在声明式上获得初值,且class编译期间需要一个class常量值(如存在数组声明式),则可用“the enum hack”补偿,使用枚举范例(enumerated type)的数值可充当ints使用的特点。
enum hack有以下特点:
[*]取enum地址不合法,可避免存在指向其的pointer或reference,进而不会导致非必要的内存分配
[*]“enum hack”是template programming(模板元编程)的基础技术
class GamePlayer {
private:
enum { NumTurns = 5 };//令NumTurns成为5的一个记号名称
int scores;
...
};形似函数的宏
类似函数的宏(macros)没有函数调用(function call)带来的额外开销,但其缺点显著,最好替换为inline函数
//带宏实参的宏,每个实参都需要加上小括号,然而还是可能出现难以预料的问题
#define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))
//使用template inline实现宏的高效以及函数的可预料性和类型安全性(type safety)
template<typename T>
inline void callWithMax(const T& a, const T& b)
{
f(a > b ? a : b);
}Tips:
[*]对于单纯常量,最好用const或enums替换#define
[*]对于形似函数的宏,最好用inline函数替换#defines
条款03:尽可能使用const(Use const whenever possible)
const和指针
[*]常量指针:const在星号*左边,则被指物是常量
[*]指针常量:const在星号*右边,则指针自身是常量
void f1(const Widget* pw);//被指物是常量
void f2(Widget const * pw);//同上STL迭代器的作用类似T*指针,其同样有指针常量和常量指针的用法
std::vector<int> vec;
...
const std::vector<int>::iterator iter = vec.begin();//指针常量
*iter = 10;//正确,改变iter所指物
++iter;//错误!iter本身是const
std::vector<int>::const_iterator cIter = vec.begin();//常量指针
*cIter = 10;//错误!*cIter是const
++cIter;//正确,改变cIter本身const成员函数
const成员函数有两个作用:
[*]使class接口容易被理解
[*]使操作const对象成为可能
//两个成员函数如果只是常量性(constness)不同,可以被重载class TextBlock {public: ... const char& operator[](std::size_t position) const//对于const对象的操作符[] { return text; } char& operator[](std::size_t position)//对于non-const对象的操作符[] { return text; }private: std::string text;};//operator[]使用方式如下TextBlock tb("Hello");std::cout
页:
[1]