《effective C++》总结【1】

时间:2019-08-22
本文章向大家介绍《effective C++》总结【1】,主要包括《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++》

    

  

  

  

原文地址:https://www.cnblogs.com/corineru/p/11380388.html