<Effective C++改善程序与设计的55个具体做法>2 构造/析构/赋值运算

条款05: Kown what functions C++ silently writes and calls.

class Empty {
}; 
等价于如下的类
class Empty{
public
  Empty(){
  };
  Empty(const Empty& rhs){
  }
  ~Empty(){
  }   
  Empty operation = (const Empty& rhs) {
  }
};
下面代码造成上述每一个函数被编译器产出:
Empty e1;     // default构造函数
              // 析构函数
Empty e2(e1); // copy构造函数 
e2 = e1;      // copy assignment操作符 

区分一下拷贝构造与拷贝赋值:

<pre name="code" class="cpp">#include <iostream>
using namespace std;

class CompareCopyAssignAndCopyCtr{
public:
  CompareCopyAssignAndCopyCtr(){
    cout << "CompareCopyAssignAndCopyCtr"<< endl;
  };	
  ~CompareCopyAssignAndCopyCtr(){
    cout << "~CompareCopyAssignAndCopyCtr"<< endl;
  };	
  CompareCopyAssignAndCopyCtr(const CompareCopyAssignAndCopyCtr&){
    cout << "Copyctr"<< endl;
  };
  CompareCopyAssignAndCopyCtr& operator=(const CompareCopyAssignAndCopyCtr&){
    cout << "Copyassign"<< endl;
    return *this;
  };
}; 

int main(int argc, char** argv) {
  CompareCopyAssignAndCopyCtr c1;
  CompareCopyAssignAndCopyCtr c2;
  cout << "---------------------"<< endl;
  CompareCopyAssignAndCopyCtr c3(c2);   //copy ctr 
  cout << "---------------------"<< endl;
  c2 = c1;                             //copy assign
  cout << "---------------------"<< endl;
  CompareCopyAssignAndCopyCtr c4 = c1; //copy ctr 
  cout << "---------------------"<< endl;
  return 0;
}
运行结果如下:

#include <iostream>
using namespace std;

template<class T> 
class NamedObject{
public:
  NamedObject(const string& name, const T& value);
  void printInfo();
private:
  string nameValue;
  T objectValue;
};

template<class T> 
NamedObject<T>::NamedObject(const string& name, const T& value){
  nameValue = name;
  objectValue = value;
};

template<class T>
void NamedObject<T>::printInfo(){
  cout << "NamedObject's Name is " << nameValue << endl;
};

int main(int argc, char** argv) {
  string newDog("Lucky");	
  string oldDog("Hasq");
  NamedObject<int> p(newDog, 2);
  NamedObject<int> s(oldDog, 36);
  p.printInfo();
  s.printInfo();
  p = s;
  p.printInfo();
  s.printInfo(); 
  return 0;
}
运行结果如下:
如果调用默认的构造函数
int main(int argc, char** argv) {
  NamedObject<int> m;
  return 0;
}
编译报错:
[Error] no matching function for call to 'NamedObject<int>::NamedObject()'
由于其中声明了一个构造函数,编译器于是不再为它创建default构造函数。为了说明这一点,再举一个例子
using namespace std;

class Fruit {
public:
  Fruit(int id);
  string s;
};

Fruit::Fruit(int id){
};

class Apple: public Fruit {
public:
  Apple();
};

Apple::Apple(){
};

int main () {
  Apple apple;
}

编译报错:
[Error] no matching function for call to 'Fruit::Fruit()'

#include <iostream>
using namespace std;
template<class T> 
class NamedObject{
public:
	NamedObject(string& name, const T& value);
	void printInfo();
private:
	string& nameValue;
	const T objectValue;
};

template<class T> 
NamedObject<T>::NamedObject(string& name, const T& value): nameValue(name), objectValue(value) {
}

template<class T>
void NamedObject<T>::printInfo(){
	cout << "NamedObject's Name is " << nameValue << endl;
};

int main(int argc, char** argv) {
	string newDog("Lucky");
	string oldDog("Hasq");
	NamedObject<int> p(newDog, 2);
	NamedObject<int> s(oldDog, 36);
	p.printInfo();
	s.printInfo();
	p = s;
	p.printInfo();
	s.printInfo(); 
	return 0;
}

编译报错:           
[Error] non-static reference member 'std::string& NamedObject<int>::nameValue', can't use default assignment operator
[Error] non-static const member 'const int NamedObject<int>::objectValue', can't use default assignment operator
结论:
①如果打算在一个“内含reference 成员”的class类支持赋值操作,必须自己定义copy assignment 操作符
②面对“内含const成员”的class类,编译器的反应也是一样。

条款06: Explicitly disallow the use of complier-generated functions you do not want.

class HomeForSale{
};

int main(int argc, char** argv) {
	HomeForSale h1;
	HomeForSale h2;
	HomeForSale h3(h1); //企图拷贝h1 --期望不该通过编译  
	h1 = h2;            //企图拷贝h2 --期望不该通过编译 
	return 0;
}
为实现阻止拷贝的作用,可将相应的成员函数声明为private并且不予实现。

class Uncopyable{
protected:
  Uncopyable(); //允许derived对象构造和析构 
  ~Uncopyable(); 
private:
  Uncopyable(const Uncopyable&);
  Uncopyable& operator=(const Uncopyable&);
}; 

Uncopyable::Uncopyable(){
};

Uncopyable::~Uncopyable(){
};

class Child: public Uncopyable{
}; 

int main(int argc, char** argv) {
	Child child1;
	Child child2;
	Child child3(child2);
	child2 = child1;
	return 0;
}

此时编译报错:

[Error] 'Uncopyable::Uncopyable(const Uncopyable&)' is private

[Error] 'Uncopyable& Uncopyable::operator=(const Uncopyable&)' is private

条款07: Declare destructors virtual in polymorphic base classes

#include <iostream>
using namespace std;

class TimeKeeper{
public:
  TimeKeeper(){
    cout << "TimeKeeper" << endl;	
  };
  ~TimeKeeper(){
    cout << "~TimeKeeper" << endl;	
   };		
};

class AtomicClock: public TimeKeeper{
public:
  AtomicClock(){
    cout << "AtomicClock" << endl;	
  };
    ~AtomicClock(){
    cout << "~AtomicClock" << endl;	
  };		
};	 

class WaterClock: public TimeKeeper{
}; 

class WristWatch: public TimeKeeper{
}; 

TimeKeeper* getTimeKeeper(int type){
  TimeKeeper* temp = NULL;
  switch(type)
  {
    case 1:
      temp = new AtomicClock();
      break;
   case 2:
     temp = new WaterClock();
     break;
   case 3:
     temp = new  WristWatch();
     break;
   default:
     break;
  }
  return temp;
}; 

int main(int argc, char** argv) {
	TimeKeeper* ptk = getTimeKeeper(1);
	delete ptk;
	return 0;
}

运行结果如下:


补充:构造和析构函数链

int main(int argc, char** argv) {
  AtomicClock ac;
  return 0;
}
运行结果如下:


结论:

derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,实际执行时通常发生的是对象的derived成分没有被销毁。

改进做法,将析构函数声明为virtual函数即可,如下所示。

class TimeKeeper{
public:
  ...
  virtual ~TimeKeeper(){
    cout << "~TimeKeeper" << endl;	
  };		
};
运行结果如下:


注意:

①带有多态(polymorphic)性质的base classes应该声明一个virtual析构函数。如果class带有任何virtual函数,它就应该拥有一个virtual析构函数(???)。

②classes的设计目的如果不是作为base classes使用,或不是为了具备多态性(polymorphically),就不该声明virtual析构函数

条款 08:Prevent exceptions from leaving destructos

#include <iostream>
using namespace std;

class DBConnection{
public:
  static DBConnection create(){
    DBConnection dbc;
    cout << "Connection Success!" << endl; 
    return dbc;  
   };
  void close(){
    cout << "Connection Close!" << endl; 
   };
}; 

class DBConn{
public:
  DBConn(){
    db = DBConnection::create();	
  } 
  void close(){                 //供客户使用的新函数 
    db.close();
    closed = true;
  };
  ~DBConn()
  {
    if (!closed) {
      try {
  	db.close();            //关闭连接(如果客户没有显示调用close()函数的话) 
	}
	catch(...){              //如果关闭动作失败,记录下来并结束程序或吞下异常 
				//制作运转记录,记下对close的调用失败   
	}
     }
  };
private:
  DBConnection db;
  bool closed;
}; 

int main(int argc, char** argv) {
  DBConn dbconn;
  return 0;
}
运行结果如下:
注意:
①析构函数绝对不要吐出异常。
②如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值