c++ 构造/析构/赋值 运算
1 为多态基类声明virtual析构函数
带有多态形态的base classs应该声明一个virtual析构函数。如果该class带有任何virtual的函数,它就应该拥有一个virtual析构函数。这样用基类指针指向的派生类的析构的时候,才会调用到自己的析构函数,将派生类的所有部分都析构掉,否则只会析构掉基类的部分,造成析构不完全、内存泄漏等问题。当创建一个纯虚的析构函数时,你必须为其提供一个定义,否则在链接的时候会出错。析构函数的运作方式是:最深层的派生(most derived)的那个class其析构函数最先被调用,然后是每一个base class的析构函数被调用。编译器会在AWOV的derived classes的析构函数中创建一个对~AWOV的调用动作。所以你必须为~AWOV提供一个定义。
class AWOV
{
public:
virtual ~AWOV() = 0; // pure virtual析构函数
};
AWOV:~AWOV(){} // pure virtual析构函数的定义
Classes的设计目的如果不是作为base classes使用的、或者不是为了具备多态性的,就不该声明virtual析构函数。如果一个class内含virtual函数,其对象的体积会变大,因为在对象模型的开始位置多了一个指向虚函数表(vptl)的虚函数指针(vptr)。STL容器中的string, vector, list, set, tr1::unordered_map等类都是没有带有virtual析构函数的,它们也不适用于当基类。
2 构造函数和析构函数的异常
构造函数可以抛出异常,然后会触发对构造出来的部分进行析构(也只有当构造函数抛出异常的时候会触发对应的析构),c++对此是保证的。
析构函数不能抛出异常,要在内部就对他进行捕获或者进行处理
析构函数绝对不要提出异常。如果一个被析构的函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下他们(不传播)或者结束程序。
如果客户需要对某个操作函数运行期间抛出的异常作出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。
3 绝不在构造和析构过程中调用virtual函数
在构造函数的过程中,base class构造函数的执行更早于derived构造函数,当base class构造函数执行时derived class的成员变量尚未初始化,若此期间调用的virtual函数是derived class的函数,则其有可能用到了derived class中那些尚未初始化的成员变量,会导致未定义的行为。实际上,上述并不会发生。因为在derived class对象的base class的构造期间,对象的类型是base class而不是derived class。不只virtual 函数会被编译器解析至base class ,若使用运行期间类型信息(runtime type infomation, 例如dynamic_cast和typeid),也会把对象视为base class类型。所以调用到virtual 函数的只会是base class层面的函数。如果在base class层面该virtual函数没有被定义(纯虚函数),则会导致链接错误;否则,调用到的函数并不是我们希望的derived class层面的virtual 函数。
相同道理也可适用于析构函数。一旦derived class析构函数开始执行时,对象内derived class成员变量便呈现未定义值。进入derived class 的析构函数时,它就被当成是base class。
4 令operator= 返回一个reference to *this
class Widget
{
public:
...
Widget& operator=(const Widger& rhs)
{
...
return *this;
}
};
这样就可以方便于写成赋值的连锁方式:
int x, y, z;
x = y = z = 20;
这个协议也适用于所有赋值相关的运算, 例如+=, -=, *=
5 复制对象时勿忘其每一个部分
Copying 函数应该确保复制“对象内的所有成员变量”及“所有base classes成分”
不要尝试以某个copying 函数实现另一个copying函数。应该将其共同机能放进第三个函数中,并由两个copying函数共同调用。
class Base
{
public:
...
Base(const Base& rhs) : name(rhs.name){}
Base& operator=(const Base& rhs)
{
name = rhs.name;
}
private:
std::string name;
};
class Derived : public Base
{
public:
Derived(const Derived& rhs) : Base(rhs), DerivedNum(rhs.DerivedNum) {}
Derived& operator=(const Derived& rhs)
{
Base::operator=(rhs);
DerivedNum = rhs.DerivedNum;
}
private:
int DerivedNum;
};

浙公网安备 33010602011771号