2、构造/析构/赋值运算

条款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=中处理“自我赋值”

  1. 证同测试

    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;
    }
    
  2. 精心周到的语句顺序保证异常安全性

    Widget& Widget::operator= (const Widget &rhs) {
    	Bitmap* pOrig = pb;
    	pb = new Bitmap(*rhs.bp);
    	delete pOrig;
    	return *this;
    }
    
  3. 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操作符。

  1. 复制所有local成员变量。
  2. 调用所有base classes内适当的copying函数。
  3. 不要尝试以某个copying函数实现另一个copying函数,应该将共同机能放进第三个函数中,并由两个copying函数共同调用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章