• 《effective C++》总结【1】


    最近开始看c++经典著作《effective c++》,总结了一些要点。

    关键字的使用

    1 自定义类的构造函数应该加上explicit,目的是为了防止隐式转换。除非有好的理由说明需要隐式转换,否则默认加上explict防止出现没有预料到的情况。

    2 对于内置类型(int, double)和STL来说,pass-by-value比pass-by-reference更加高效,但是对于自定义的类,pass-by-reference比pass-by-value更加高效。

    3 由于#define定义的宏常量可能没有进入到记号表,导致追踪不到。我是从来没遇到过这种情况,但是作者还是建议在众多场合不要使用#define。

    • 定义常量整数或实数时,尽量用const int或const double代替。这会导致更少量的码。
    • 定义常量指针时,要用两次const。const char* authorname = “scott meyers”。
    • 定义类中的常量时,还要用static修饰。
    • 定义类中的数组时,必须要定义常量,这时如果编译器不允许在类内声明时定义常数,就可以用enum代替。例如

      class GamePlayer{

      private:

        enum { NumTurns = 5};

        int scores[NumTurns];

      }

      enum的行为比较像#define而不像const。例如取一个enum的地址是不合法的,而取一个#define的地址通常也不合法。

    • 用template inline函数代替#define函数

      错误用法:#define CALL_WITH_MAX(a, b)  f((a) > (b) ? (a) : (b))

      正确用法:template<typename T>

      inline void callwithmax(const T&a, const T& b)

      {

        f(a > b ? a : b);

      }

    4 多用const关键字可帮助编译器侦测出错误用法。const语法虽然变化多端,但并不莫测高深。如果关键字const出现在星号左边,表示被指物是常量。如果const出现在星号右边,表示指针自身是常量。如果出现在星号两边,表示被指物和指针两者都是常量。

    • const用于返回值,避免返回值被赋值。

      class Rational {...};

      const Rational operator*(const Rational& a, const Rational & b); 此处之所以要返回一个const对象是为了防止给返回值赋值这样的暴行,比如if( (a*b)=c)这样无意识的错误。

      这样做可以保持与内置类型兼容。如果a和b都是内置类型,这样的代码直截了当就是不合法。因此自定义类型最好也保持这样。

    • const用于成员函数,两个成员函数若只是常量属性不同,可以被重载(也就是说是两个不同的函数)。const成员函数只能更改const成员,而不能更改non-static成员变量。

      如果要让const成员函数修改部分成员变量,可以使用mutable关键字来解禁。

      为了避免const和non-const成员函数中代码重复,可以在non-const成员函数中调用const函数,反之不可

      class TextBlock{

      public:

      const char& operator[](size_t position) const

      {

        ...

        return text[position];

      }

      char & operator[](size_t position) 

      {

        return const_cast(static_cast<const& TextBlock>(*this)[position]);

      }

    5 确定对象在调用之前已经被初始化了。

      如果遇到一个全局对象A调用另一个全局对象B时,必须要保证B在A之前先被初始化了。

      为了避免可能会忘记先后顺序的操作,可以将全局对象放进函数内(该对象在此函数内声明为static),并在函数内返回一个reference指向它所含的对象。

      class FileSystem {...}

      FileSystem& tfs()

      {

        static FileSystem fs;  //定义并初始化fs

        return fs;

      }

      class Directory {..};

      Directory::Directory(params)

      {

        std::size_t disks = tfs().numDisks();   //调用FileSystem类

      }

      Directory & tempDir()

      {

        static Directory td;   //定义并初始化对象

        return td;

      }

    构造/析构/赋值 

    6 编译器会自动生成构造、析构、赋值等函数,但如果用户自定义了构造函数,则会覆盖原来的默认构造函数。

    7 为了禁止拷贝等行为,可以将成员函数声明为private并不予实现。

    8 任何class只要带有virtual函数都几乎确定应该也有一个virtual析构函数。如果class不含virtual函数,通常表示它并不意图被用做一个base class。当class不企图被当作base class,令其析构函数为virtual往往是个馊主意。

    9 不建议继承标准容器或者带有非virtual析构函数的class。比如class SpecialString:public string是不建议的。因为string类内部不含有virtual函数,可能会导致未定义行为。

    10 不要在析构函数中吐出异常。如果析构函数中需要调用可能抛出异常的函数,析构函数应该捕捉任何异常,然后吞下他们从而不让异常传播。如果客户需要对某个函数运行期间抛出的异常作出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。

    11 在构造函数和析构函数中,都不应调用virtual函数。

    12 当为派生类写拷贝构造函数或等号操作符时,要记得把基类也一并拷贝。

    参考:《effective c++》

  • 相关阅读:
    Mysql性能优化
    PHP IF判断简写
    PHP与MYSQL事务处理
    js获取select标签选中的值
    oralce 的安装以及plsql的配置的html连接
    mysql 中启动服务的命令 、登录命令、退出命令 mysql 的常用命令
    oracle 中 某个字段的长度不够的sql 语句
    随机获得id的方法
    java中解析excel 批量插入数据库
    java 调用存储过程
  • 原文地址:https://www.cnblogs.com/corineru/p/11380388.html
Copyright © 2020-2023  润新知