1、了解C++默默编写并调用哪些函数
*至于copy构造函数和copy assignment操作符,编译器创建的版本只是单纯地将来源对象的每一个non-static 成员变量拷贝到目标对象。注意,编译器产出的析构函数是个non-virtual。
*如果你打算在一个"内含reference 成员"的 class 内支持赋值操作 (assignment) ,你必须自己定义 copy assignment 操作符。面对"内含 const 成员" (如本例之 objectValue) 的classes ,编译器的反应也一样。更改 const 成员是不合法的,所以编译器不知道如何在它自己生成的赋值函数内面对它们。最后还有一种情况:如果某个 base classes 将copy assignment
操作符声明为 private ,编译器将拒绝为其 derived classes 生成一个 copy assignment 操作符。毕竟编译器为 derived classes 所生的 copy assignment 操作符想象中可以处理 base class 成分 ,但它们当然无法调用 derived class 无权调用的成员函数。
操作符声明为 private ,编译器将拒绝为其 derived classes 生成一个 copy assignment 操作符。毕竟编译器为 derived classes 所生的 copy assignment 操作符想象中可以处理 base class 成分 ,但它们当然无法调用 derived class 无权调用的成员函数。
2、若不想使用编译器自动生成的函数,就该明确拒绝
方法一:直接将本类的copy构造函数和copy assignment操作符声明为private;
方法二:设计一个专门为了阻止copying动作的baseclass,让那些不想使用编译器自动生成类继承这具baseclass.实现如下:
class Uncopyable
{
protected: //允许derived对象构造和析构
Uncopyable() {}
-Uncopyable(} { }
private:
Uncopyable(constUncopyable&}; //但阻止copying
Uncopyable& operator=(constUncopyable&);
};
class D:private Uncopyable
{...};
只要任何人一一甚至是member函数或friend函数一一尝试拷贝D对象,编译器便试着生成一个copy构造函数和-个copyass够nment操作符,而正如条款12所说,这些函数的"编译器生成版"会尝试调用其base class的对应兄弟,那些调用会被编译器拒绝,因为其baseclass的拷贝函数是private。
3、为多态墓类声明virtual析构函数
*通过指针指向一个derived class 对象 ,而那个对象却经由一个base class指针被删除,而目前的baseclass 有个non-virtual析构函数。那么,实际执行时通常发生的是对象的 derived 成分没被销毁。derived class的析构函数也没有被执行起来。从而使对象只是被局部撤销。解决方法:给baseclass一个virtual析构函数。
*不要继承STL中定义的类型和容器,因为他们不是设计成基类来用作继承的,它们的析构函数是不带virtual的。
*而有时候你希望拥有抽象class,但手上没有任何pure virtual函数,怎么办?解决方法:由于抽象class总是企图被当作一个baseclass来用,而又由于baseclass应该有个virtual析构函数,并且由于pure virtual函数会导致抽象class,因此解法很简单:为你希望它成为抽象的那个class声明一个pure virtual
析构函数。
4、到让异常逃离析构函数
*析构函数绝对不要吐出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结束程序。
*如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么 class 应该提供一个普通函数(而非在析构函数中)执行该操作。
class DBConn
{
public:
void close( ) //供客户使用的新函数
{
db.close( );
closed = true;
}
~DBConn ()
{
if (! closed) {
try { //关闭连接(如果客户不那么做的话)
db. close( );
}
catch (...) {
制作运转记录,记下对close的调用失败;
//如果关闭动作失败,
// 记录下来并结束程序
// 或吞下异常。
}
}
}
private:
DBConnection db;
bool closed;
};
5、绝不在构造和析构过程申调用 virtual 函数
*base class 构造期间virtual 函数绝不会下降到derived classes阶层。取而代之的是,对象的作为就像隶属base类型一样。非正式的说法或许比较传神:在baseclass构造期间,virtual函数不是virtual函数。
*原因:1、由于base class 构造函数的执行更早于derivedclass构造函数,当baseclass构造函数执行时derivedclass的成员变量尚未初始化。如果此期间调用的virtual函数下降至derivedclasses阶层,要知道derivedclass的函数几乎必然取用local成员变量,而那些成员变量尚未初始化。2、在derivedclass对象的baseclass构造期间,对象的类型是 base
class 而不是 derived class。
class 而不是 derived class。
*注意:很多时候为了避免代码重复,把virtual函数放在另一个函数中,但构造和析构函数中调用此函数,则此错误就更隐蔽,更难发现。
6、复制对象时勿忘其每一个成分
*Copying函数应该确保复制"对象内的所有成员变量"及"所有baseclass成分"。
*不要尝试以某个copying函数实现另一个copying函数。应该将共同机能放进第三个函数中,并由两个coping函数共同调用。