文章目录
条款05:了解C++默默编写并调用哪些构造函数
编译器会自动生成,并且仅当生成的代码合法以及这些函数会被调用时,才会被创建出来:
(1) 默认构造函数
(2) copy构造函数
(3) 析构函数
(4) 赋值操作符(=):内含reference成员、内含const成员、基类的operator=为private,这三种情况不会自动生成=操作符。
条款06:若不想使用编译器自动生成的函数,就该明确拒绝
1、将成员函数声明为private而且故意不实现他们(member函数或者friend函数调用会导致link报错)
class HomeForSale {
public:
...
private:
...
HomeForSale(const HomeForSale &);
HomeForSale& operator= (cons HomeForSale &);
};
2、设计一个不允许copying动作的基类
class Uncopyable {
protected:
Uncopytable() {}
~Uncopytable() {}
private:
Uncopytable (const Uncopytable &);
Uncopytable& operator= (const Uncopytable &);
};
条款07:为多态基类声明virtual析构函数
虚函数是指一个类中希望重载的成员函数,当用一个基类指针或引用指向一个继承类对象的时候,调用虚函数实际上调用的是继承类的版本。
当继承类对象经由基类指针被删除,并且基类的析构函数是non-virtual,结果未定义,实际执行时通常发生的是对象的继承部分没有被销毁。所以对于带多态性质的基类应该要声明一个virtial析构函数,反之则不该声明virtual析构函数(由于虚函数表的存在,会使对象体积增加)。
条款08:别让异常逃离析构函数
析构函数不要吐出异常,否则要应该要对异常进行捕捉,并处理或结束程序。
考虑下述代码,当dosomething()函数结束时,会逐个调用vector v中每个Widget对象的析构函数,假设有两个Widget对象的析构抛出异常,就会导致不明确行为。
class Widget {
public:
...
~Widget() {...}
};
void dosomething()
{
std::vector<Widget> v;
...
}
条款09:绝不在构造和析构过程中调用virtual函数
base class构造期间virtual函数绝不会下降到derived class阶层,即在base class构造期间,virtual函数不是virtual函数。因为在derived class对象的base class构造期间,对象类型是base class,而不是derived class;析构函数也是同理,derived class对象的析构函数先调用,然后触发base class对象的析构函数,此时对象的类型也是base class。
class Transaction {
public:
Transaction();
virtual void logTransaction() const = 0;
...
};
Transaction::Transaction() {
...
logTransaction();
}
class SellTransaction: public Transaction {
public:
virtual void logTransaction() const;
...
};
SellTransaction s; // base class的构造函数调用的是base class的logTransaction
条款10:令operator=返回一个reference to *this
赋值动作采用右结合律,即
int x, y, z;
x = y = z = 15; //-->
x = ( y = ( z = 15));
所以为了实现这种连锁赋值,赋值操作符必须返回一个reference指向操作符的左侧实参:
class Widget {
public:
...
Widget& operator= (const Widget &rhs) {
...
return *this;
}
};
条款11:在operator=中处理“自我赋值”
-
证同测试
class Bitmap {...}; class Widget { ... private: Bitmap *bp; }; Widget& Widget::operator= (const Widget &rhs) { if (this == &rhs) return *this; delete pb; pb = new Bitmap(*rhs.pb); return *this; }
-
精心周到的语句顺序保证异常安全性
Widget& Widget::operator= (const Widget &rhs) { Bitmap* pOrig = pb; pb = new Bitmap(*rhs.bp); delete pOrig; return *this; }
-
copy and swap
class Widget {
...
void swap(Widget& rhs);
...
};
Widget& Widget::operator= (const Widget &rhs) {
Widget tmp(rhs);
swap(tmp);
return *this;
}
条款12:复制对象时勿忘其每一个成分
copying函数就是copy构造函数和copy assignment操作符。
- 复制所有local成员变量。
- 调用所有base classes内适当的copying函数。
- 不要尝试以某个copying函数实现另一个copying函数,应该将共同机能放进第三个函数中,并由两个copying函数共同调用。