effective C++之构造、析构、赋值运算

条款05:了解C++默默编写了并调用了那些函数

编译器会声明一个copy构造函数,一个copy assignment 操作符合一个析构函数所有这些函数都是public和inline的

如果打算在一个内含reference 成员的class内支持赋值操作你必须自己定义copy assignment 操作符面对const成员的classes编译器反应也一样。

另一种情况:如果某个base class将assignment操作符声明为private编译器将拒绝为derived class 生成一个copy assignment 操作符

请记住

@编译器可以暗自为class 创建default构造函数,copy构造函数,copy assignment 操作符,以及析构函数

条款06 如果不想使用编译器自动生成的函数就应该明确的拒绝

有个class 用来描述待售房

class HomeForSale{};

任何一笔资产都是独一无二的那么该class不该存有副本

HomeForSale h1;

HomeForSale h2;

HomeForSale h3(h1)//企图拷贝h1 —-编译不应该通过

h1=h2;/编译不应该通过

为解决以上问题

可以讲copy构造函数和copy assgiment 操作符声明为private来阻止编译器暗自创建其专属版本。但这也不是绝对的安全因为member函数和friend函数还是可以调用你的private函数。最好的方法是不去定义他们即将成员函数声明为private而且故意不提供实现他们。

那么HomeForSale可以这样的改写

class HomeForSale{

private:

HomeForSale(const HomeForSale&);//只是声明不去实现

HomeForSale& operator=(const HomeForSale&);//同上

};

很多情况下我们专门设计一个阻止copying动作的base class像这样

class Uncopyable{

proctected:

Uncopyable(){}

~Uncopyable(){}

private:

Uncopyable(const Uncopyable&);

Uncopyable& operator=(const Uncopyable&);

};

其他类只需继承此类便可获取阻止copying行为(boost 库提供 class noncopyable来实现阻止copying行为)

请记住:

@为驳回编译自动(暗自)提供的机能,可将相应成员函数声明为private并且不予以实现.使用像Uncopyable这样的base class 也是一种做法

条款07:为多态的基类,声明virtual析构函数

class TimeKeeper{

public:

TimeKeeper();

~TimeKeeper();

};

class AtomicClock:public TimeKerrper{…}

class WaterClock:public TimeKeeper{…}

我们这样的到对象指针:

TimeKeeper* getTimeKeeper();//指向一个派生类动态分配的对象指针

TimeKeeper*ptk=getTimeKeeper();

delete ptk;

以上会导致一些问题C++明白的指出当derived对象经由一个base class 指针删除时而该base class带着一个non-virtual 析构函数那么结果是未有定义的通常不会释放derive的成分

消除问题很简单为base class 提供一个virual 析构函数

但如果class 不含vitual函数那么通常情况下他并不意图被当做一个base class 如果令其析构函数为virtual 那么行为也将是糟糕的因为含有virtual函数的对象其内部维护了一个vptr指针其对象将会比一般不带virual函数的对象要大

还有一个问题需注意:

class SpecialString:public string//string有个non virual析构函数

{

};

如果你在程序中无意间将一个pointer to SpecialString转化为一个pointer to string然后delete掉,就会出现行为不明确

string有个non virual析构函数

有时候让class带一个pure virtual 析构函数可能会更加的便利(同时要为此析构函数提共一份定义否则编译器会抱怨的)

class AWOV

{

public:

virtual ~AWOV()=0;

};

AWOV::~AWOV(){}

上面这种情况只适用于带多态性质的base class 身上

请记住:

@polymorphic(带多态性质的)base class 应该声明一个virtual析构函数如果class带有任何virtual 函数,他就该拥有一个virtual析构函数.

@Classes 的设计目的如果不是作为base class 适用,或者不是为了具备多态性质就不该声明为virual析构函数

条款08:别让异常逃离析构函数

C++不鼓励你在析构函数中吐出异常

如果你的析构函数必须执行一个动作而该动作可能会在失败的时候抛出异常例如:

class DBConnection{

public:

static DBConnection Create();

void close();

}

为了 确保客户在DBConnection对象身上调用close()一个合理的想法是创建一个用来管理BDconnection资源的class

class DBConn

{

~DBConn()

  {db.close()}

private:

DBConnection db;

}

close()调用成功一切美好,但如果该调用导致了异常DBConn会将该异常传播也就是允许他离开该析构函数那么就会造成问题.

我们通常有一下方式改善

1 如果close抛出异常就结束程序通常用abort完成

DBConn::~DBConn(){try{db.close()}catch (…){std::abort();}}

强制结束程序

2 吞下因调用close而发生的异常

DBConn::~DBConn(){try{ db.close(); }catch (…){……….}}

不管这个异常仍然继续执行

3最佳的做法是重新设计DBConn接口使用户有机会在对可能出现问题作出反应如下

而是深沉的意志恢弘的想象炙热的恋情;青春是生命的深泉在涌流。

effective C++之构造、析构、赋值运算

相关文章:

你感兴趣的文章:

标签云: