Effective C++

  • 导读

  1. 被声明为explicit的构造函数禁止编译器执行隐式类型转换,除非有好理由允许构造函数被用于隐式类型转换,否则把它声明为explicit。
  2. 拷贝构造操作与拷贝赋值操作。(对象之前是否被定义)
  3. Pass-by-valuePass-by-reference。对于用户自定义类型,Pass-by-reference-const往往是比较好的选择。
  • 条款01:视C++为一个语言联邦(View C++ as a federation of languages

  1. C++并不是一个带有一组守则的一体语言;它是从四个次语言组成的联邦政府,每个次语言有自己的规约。
  1. C (以C为基础的C++)
  2. Object-Oriented C++ (C with Classes 面向对象,封装、继承、多态,构造、析构、虚函数等特性)
  3. Template C++ (泛型编程、模板元)
  4. STL (标准程序库,分配器、容器、迭代器、算法、适配器、仿函数)
  1. C++高效编程守则视状况而变化,取决于你用C++的哪一部分。
  • 条款02:尽量以const,enum,inline替换#define (Prefer consts,enums,and inlines to #define

  1. 以常量替换#define场景一:定义常量指针

const char* const authorName = "Scott Meyers";
string对象通常比其前辈char*-based合宜
const std::string authorName("Scott Meyers");

  1. 以常量替换#define场景二:定义类专属常量

在类中使用常量申明式 static const int NUM = 5;
或者在类内声明,类外定义const int GamePlayer::NUM = 5;
如果编译器不允许static const int在类内进行初值的设定,可改用”the enum hack“做法

class GamePlayer {
private:
    enum { NUM = 5 };
    int scores[NUM];  
};
  1. enum hack的行为某方面比较像#define而不像const,取一个const的地址是合法的,但取一个enum的地址或#define的地址就不合法,如果不想让别人获得一个pointerreference指向你的某个整数常量,enum可以帮助实现这个约束。

  2. C语言中宏函数一定程度上类似于C++中的模板函数,编写宏函数时为了避免不必要的麻烦,所有实参加上小括号。

  3. 通过template inline函数来替换宏函数来保证类型安全性。

    //以a和b的较大值调用函数f
    #define CALL_WITH_MAX(a,b) f((a) > (b) ? (a) : (b))
    //使用内联函数模板替换
    template<typename T>
    inline coid callWithMax(const T& a, const T& b)
    {
        f(a > b ? a : b);
    }
    
  4. 对于单纯常量,最好以const对象或enum替换#define

  5. 对于形似函数的宏,最好改用inline函数替换#define

  • 条款03 尽可能使用const (Use const whenever possible

  1. 多才多艺的const,如果关键字const出现在星号左边,表示被指物是常量;如果出现在星号右边,表示指针自身是常量;如果出现在星号两边,表示被指物和指针两者都是常量。

const std::vector<int>::iterator iter类似于T* const,迭代器本身就是常量,指向的地址不变
std::vector<int>::const_iterator cIter类似于const T*,迭代器指向的内容不

  1. 在一个函数声明式内,const可以和函数返回值、各参数、函数自身(如果是成员函数)产生关联。

const Rational operator* (const Rational& lhs, const Rational& rhs);

  1. 将const实施于成员函数的目的,是为了确认该成员函数可作用于const对象身上。这样使class接口比较容易理解,可以得知那个成员函数可以改动对象内容而哪个不行。

  2. 两个成员函数如果只是常量属性不同,可以被重载。

    class TextBlock {
    public:
        //operator[] for const 对象
        const char& operator[] (std::size_t position) const { return text[position]; }
        //operator[] for non-const 对象
        char& operator[] (std::size_t position) { return text[position]; }
    private:
        std::string text;
    };
    
    TextBlock tb("Hello");
    std::cout << tb[0];     //调用non-const TextBlock::operator[]
    
    const TextBlock ctb("world");
    std::cout << ctb[0];    //调用const TextBlock::operator[]
    
    //真实程序中const对象大多用于passed by pointer-to-const 
    //或 passed by reference-to-const 传递结果
    void print(const TextBlock& ctb)
    {
        std::cout << ctb[0];
    }
    
  3. 注意non-const operator[]返回类型是个reference to char,不是char。如果返回的是char,是以pass by value的形式传值,返回的是一个副本,不是对象本身,如果做出tb[0] = 'x'的动作,达不到想要的效果。

  4. 将某些东西声明为const可以帮助编译器侦测出错误写法。const对象可被施加于任何作用域内的对象、函数参数、函数返回值、成员函数本体。

  5. 当const 和 non-const 成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复。

  • 条款04:确定对象被使用前已先被初始化 (Make sure that objects are initialized before they're used

posted @ 2019-12-23 16:13  小蜗牛慢跑  阅读(140)  评论(0编辑  收藏  举报