《Effective C++》第三版-1. 让本身风俗C++(Accustoming Yourself to C++ ...

打印 上一主题 下一主题

主题 864|帖子 864|积分 2592

目录

条款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)

该条款可表达为:宁可以编译器替换预处理器
替换原因
  1. #define ASPECT_RATIO 1.653
  2. 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
  1. const char* const authorName = "Scott Meyers";
  2. const std::string authorName("Scott Meyers");  //使用string更合适
复制代码
class专属常量:为了将常量作用于(scope)限制在class内,需要让其成为class的一个成员(member);为了确保此常量至多只有一份实体,需要让其成为static成员
  1. class GamePlayer {
  2. private:
  3.         static const int NumTurns = 5;  //常量声明式
  4.         int scores[Numturns];  //使用该常量
  5.         ...
  6. };
复制代码
当某个东西是class专属常量+static+整数范例(integral type,如ints、chars、bools),只要不取地址,则可是有声明式而无定义式,否则需要提供定义式。
  1. //应放入实现文件而非头文件
  2. const int Gameplayer::NumTurns;  //NumTurns的定义,声明时设定了初值故此处可不设定值
复制代码
旧编译器可能不允许static成员在声明式上获得初值,此时可将初值放在定义式。
  1. class CostEstimate {
  2. private:
  3.         static const double FudgeFactor;  //static class常量声明,位于头文件
  4. };
  5. 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(模板元编程)的基础技术
  1. class GamePlayer {
  2. private:
  3.         enum { NumTurns = 5 };  //令NumTurns成为5的一个记号名称
  4.         int scores[NumTurns];
  5.         ...
  6. };
复制代码
形似函数的宏

类似函数的宏(macros)没有函数调用(function call)带来的额外开销,但其缺点显著,最好替换为inline函数
  1. //带宏实参的宏,每个实参都需要加上小括号,然而还是可能出现难以预料的问题
  2. #define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))
  3. //使用template inline实现宏的高效以及函数的可预料性和类型安全性(type safety)
  4. template<typename T>
  5. inline void callWithMax(const T& a, const T& b)
  6. {
  7.         f(a > b ? a : b);
  8. }
复制代码
Tips:

  • 对于单纯常量,最好用const或enums替换#define
  • 对于形似函数的宏,最好用inline函数替换#defines
条款03:尽可能使用const(Use const whenever possible)

const和指针


  • 常量指针:const在星号*左边,则被指物是常量
  • 指针常量:const在星号*右边,则指针自身是常量
  1. void f1(const Widget* pw);  //被指物是常量
  2. void f2(Widget const * pw);  //同上
复制代码
STL迭代器的作用类似T*指针,其同样有指针常量和常量指针的用法
  1. std::vector<int> vec;
  2. ...
  3. const std::vector<int>::iterator iter = vec.begin();  //指针常量
  4. *iter = 10;  //正确,改变iter所指物
  5. ++iter;  //错误!iter本身是const
  6. std::vector<int>::const_iterator cIter = vec.begin();  //常量指针
  7. *cIter = 10;  //错误!*cIter是const
  8. ++cIter;  //正确,改变cIter本身
复制代码
const成员函数

const成员函数有两个作用:

  • 使class接口容易被理解
  • 使操作const对象成为可能
[code]//两个成员函数如果只是常量性(constness)不同,可以被重载class TextBlock {public:        ...        const char& operator[](std::size_t position) const  //对于const对象的操作符[]        { return text[position]; }        char& operator[](std::size_t position)  //对于non-const对象的操作符[]        { return text[position]; }private:        std::string text;};//operator[]使用方式如下TextBlock tb("Hello");std::cout
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

立聪堂德州十三局店

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表