您的位置:首页 > 编程语言 > C语言/C++

Effective C++ 3nd 读书摘要(一、让自己习惯C++ ; 二、构造,析构,赋值运算)Item1 - 12

2009-06-01 16:44 826 查看
一、让自己习惯C++
Item1. 视C++为一个语言联邦
C++由以下部分组成:C、Object-Oriented C++、Template C++、STL



Item2. 尽量以const、enum、inline代替#define



Item3. 尽可能使用const
1.一共有这样几种const用法:
char greeting[] = "Hello";
char *p = greeting; // non-const pointer, non-const data
const char *p = greeting; // non-const pointer, const data
char * const p = greeting; // const pointer, non-const data
const char * const p = greeting; // const pointer, const data



另外,以下两种形式是一样的:
void f1(const Widget *pw); // f1 takes a pointer to a constant Widget object
void f2(Widget const *pw); // so does f2



迭代器也有const:
const std::vector<int>::iterator iter = // iter acts like a T* const
std::vector<int>::const_iterator cIter = //cIter acts like a const T*



2. 让non-const函数调用const函数以避免重复:

const char& operator[](std::size_t position) const     // same as before
  {
    ...
    return text[position];
  }

  char& operator[](std::size_t position)         // now just calls const op[]
  {
    return
      const_cast<char&>(                                   // cast away const on op[]'s return type;
        static_cast<const TextBlock&>(*this)     // add const to *this's type;
          [position]                            	    // call const version of op[]
      );
  }


const函数可以使得返回的const指针、const引用等等均可以调用一些方法(const对象只能调用const函数)



Item4. 确保对象在使用前已经先被初始化
重要的是不能混淆赋值(assignment)与初始化(initialization),通常后者的效率更高,初始化通过成员初值列表。最好以申明次序作为成员列表中的次序。



Singleton模式的一个应用:定义于不同编译单元的non-local static对象的初始化次序

class FileSystem { ... };           // as before
FileSystem& tfs()                   // this replaces the tfs object; it could be
{                                   // static in the FileSystem class
  static FileSystem fs;             // define and initialize a local static object
  return fs;                        // return a reference to it
}

class Directory { ... };            // as before

Directory::Directory( params )      // as before, except references to tfs are
{                                   // now to tfs()
  ...
  std::size_t disks = tfs().numDisks();
  ...
}

Directory& tempDir()                // this replaces the tempDir object; it
{	                                   // could be static in the Directory class
  static Directory td;              // define/initialize local static object
  return td;	           // return reference to it
}


即以local static对象代替non-local static对象



二、构造、析构、赋值运算
Item5. 了解C++默默编写并调用了哪些函数
这些是C++会默认生成的(如果你没有定义):copy构造、copy assignment、析构(non-virtual)、default构造,所有这些都是public而inline的。

(注:上面的析构(non-virtual),除非其base class是虚析构)



Item6. 若不想使用编译器自动生成的函数,就该明确拒绝
接Item5所言,要想拒绝之:

class HomeForSale {
public:
  ...
private:
  ...
  HomeForSale(const HomeForSale&);            // declarations only
  HomeForSale& operator=(const HomeForSale&);
};


也可以建一个base class,这样还可以把连接期错误移到编译期:

class Uncopyable {
protected:                                   // allow construction
  Uncopyable() {}                            // and destruction of
  ~Uncopyable() {}                           // derived objects...
private:
  Uncopyable(const Uncopyable&);             // ...but prevent copying
  Uncopyable& operator=(const Uncopyable&);
};


我们只要继承自此类:

class HomeForSale: private Uncopyable { // class no longer
... // declares copy ctor or copy assign. operator
};



Item07. 为多态基类声明virtual析构函数
否则当用base class pointer来delete那个derived class对象时会造成局部销毁。

如果class带有任何virtual函数,base class就应该带有一个virtual析构函数。否则不该用。



Item08. 别让异常逃离析构函数
如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结

束程序。
较好的一种做法是:

class DBConn {
public:
  ...
  void close()                                     // new function for
  {                                                      // client use
    db.close();
    closed = true;
  }
  ~DBConn()
   {
   if (!closed) {
   try {                                            // close the connection
     db.close();                                    // if the client didn't
   }
   catch (...) {                                    // if closing fails,
     make log entry that call to close failed;   // note that and
     ...                                             // terminate or swallow
   }
  }
private:
  DBConnection db;
  bool closed;
};


给客户一次调用close处理错误的机会。



Item09. 绝不在构造和析构过程中调用virtual函数
因为在base class构造期间对象的类型还是base class而不是derived classe(此时的virtual函数不是virtual函数,而只是个base class的函数),derived class成分尚为未定义值。

同样,一旦derived class析构函数开始执行,对象内的derived class成员变量便呈现未定义值,那么当进入

base class析构函数后对象就成为一个base class对象。



一种弥补方法是令derived classes将必要的构造信息向上传递至base class构造函数。

class Transaction {
public:
  explicit Transaction(const std::string& logInfo);
  void logTransaction(const std::string& logInfo) const;   // now a non-virtual func
  ...
};

Transaction::Transaction(const std::string& logInfo)
{
  ...
  logTransaction(logInfo);                                // now a non-virtual call
}

class BuyTransaction: public Transaction {
public:
 BuyTransaction( parameters )
 : Transaction(createLogString( parameters ))             // pass log info
  { ... }                                                 // to base class
   ...                                                    // constructor
private:
  static std::string createLogString( parameters );
};




Item10. 令operator=返回一个reference to *this
这样可以支持x=y=z=15这样的赋值连锁形式。



Item11. 在operator=中处理“自我赋值”
其中可以用到的技术有:
1. 比较“来源对象”和“目标对象”的地址 if(this == & rhs) return * this;
2. 精心周到的语句顺序

Widget&
Widget::operator=(const Widget& rhs)              // unsafe impl. of operator=
{
  delete pb;                                      // stop using current bitmap
  pb = new Bitmap(*rhs.pb);                       // start using a copy of rhs's bitmap
  return *this;                                   // see Item 10
}


3. copy-and-swap

class Widget {
  ...
  void swap(Widget& rhs);   // exchange *this's and rhs's data;
  ...                       // see Item 29 for details
};

Widget& Widget::operator=(const Widget& rhs)
{
  Widget temp(rhs);             // make a copy of rhs's data
  swap(temp);                   // swap *this's data with the copy's
  return *this;
}




Item12. 复制对象时勿忘其每一个成分
1.要确保(1)复制所有local成员变量;(2)调用所有base classes内的适当的copying函数(copy constructor或copy assignment)

2.不要尝试以一个copying函数实现另一个copying函数,而应该将共同功能放进第三个函数中。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: