码迷,mamicode.com
首页 > 编程语言 > 详细

《effective C++》总结【1】

时间:2019-08-22 22:00:48      阅读:105      评论:0      收藏:0      [点我收藏+]

标签:cas   类型兼容   意图   一个   实现   virtual   需要   sys   director   

最近开始看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++》

    

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

  

  

《effective C++》总结【1】

标签:cas   类型兼容   意图   一个   实现   virtual   需要   sys   director   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!