找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 1748|回復(fù): 0
收起左側(cè)

拷貝構(gòu)造函數(shù)和賦值構(gòu)造函數(shù)聲明為私有的作用

[復(fù)制鏈接]
ID:107189 發(fā)表于 2016-3-6 02:07 | 顯示全部樓層 |閱讀模式
每個(gè)類只有一個(gè)賦值函數(shù).

  由于并非所有的對象都會(huì)使用拷貝構(gòu)造函數(shù)和賦值函數(shù),程序員可能對這兩個(gè)函數(shù)有些輕視。請先記住以下的警告,在閱讀正文時(shí)就會(huì)多心:
  1.如果不主動(dòng)編寫拷貝構(gòu)造函數(shù)和賦值函數(shù),編譯器將以“位拷貝”的方式自動(dòng)生成缺省的函數(shù)。倘若類中含有指針變量,那么這兩個(gè)缺省的函數(shù)就隱含了錯(cuò)誤。以類String的兩個(gè)對象a,b為例,假設(shè)a.m_data的內(nèi)容為“hello”,b.m_data的內(nèi)容為“world”。
  現(xiàn)將a賦給b,缺省賦值函數(shù)的“位拷貝”意味著執(zhí)行b.m_data = a.m_data。這將造成三個(gè)錯(cuò)誤:一是b.m_data原有的內(nèi)存沒被釋放,造成內(nèi)存泄露;二是b.m_data和a.m_data指向同一塊內(nèi)存,a或b任何一方變動(dòng)都會(huì)影響另一方;三是在對象被析構(gòu)時(shí),m_data被釋放了兩次。
  2.拷貝構(gòu)造函數(shù)和賦值函數(shù)非常容易混淆,常導(dǎo)致錯(cuò)寫、錯(cuò)用。拷貝構(gòu)造函數(shù)是在對象被創(chuàng)建時(shí)調(diào)用的,而賦值函數(shù)只能被已經(jīng)存在了的對象調(diào)用。以下程序中,第三個(gè)語句和第四個(gè)語句很相似,你分得清楚哪個(gè)調(diào)用了拷貝構(gòu)造函數(shù),哪個(gè)調(diào)用了賦值函數(shù)嗎?
  String a(“hello”);
  String b(“world”);
  String c = a; // 調(diào)用了拷貝構(gòu)造函數(shù),最好寫成 c(a);
  c = b; // 調(diào)用了賦值函數(shù)
  本例中第三個(gè)語句的風(fēng)格較差,宜改寫成String c(a) 以區(qū)別于第四個(gè)語句。
  類String的拷貝構(gòu)造函數(shù)與賦值函數(shù)
  // 拷貝構(gòu)造函數(shù)
  String::String(const String &other)
  {
  // 允許操作other的私有成員m_data
  int length = strlen(other.m_data);
  m_data = new char[length+1];
  strcpy(m_data, other.m_data);
  }
  // 賦值函數(shù)
  String & String::operate =(const String &other)
  {
  // (1) 檢查自賦值
  if(this == &other)
  return *this;
  // (2) 釋放原有的內(nèi)存資源
  delete [] m_data;
  // (3)分配新的內(nèi)存資源,并復(fù)制內(nèi)容
  int length = strlen(other.m_data);
  m_data = new char[length+1];
  strcpy(m_data, other.m_data);
  // (4)返回本對象的引用
  return *this;
  }
  類String拷貝構(gòu)造函數(shù)與普通構(gòu)造函數(shù)的區(qū)別是:在函數(shù)入口處無需與NULL進(jìn)行比較,這是因?yàn)椤耙谩辈豢赡苁荖ULL,而“指針”可以為NULL。
  類String的賦值函數(shù)比構(gòu)造函數(shù)復(fù)雜得多,分四步實(shí)現(xiàn):
 。1)第一步,檢查自賦值。你可能會(huì)認(rèn)為多此一舉,難道有人會(huì)愚蠢到寫出 a = a 這樣的自賦值語句!的確不會(huì)。但是間接的自賦值仍有可能出現(xiàn),例如
  // 內(nèi)容自賦值
  b = a;
  …
  c = b;
  …
  a = c;
  // 地址自賦值
  b = &a;
  …
  a = *b;
  也許有人會(huì)說:“即使出現(xiàn)自賦值,我也可以不理睬,大不了化點(diǎn)時(shí)間讓對象復(fù)制自己而已,反正不會(huì)出錯(cuò)!”
  他真的說錯(cuò)了。看看第二步的delete,自殺后還能復(fù)制自己嗎?所以,如果發(fā)現(xiàn)自賦值,應(yīng)該馬上終止函數(shù)。注意不要將檢查自賦值的if語句
  if(this == &other)
  錯(cuò)寫成為
  if( *this == other)
  (2)第二步,用delete釋放原有的內(nèi)存資源。如果現(xiàn)在不釋放,以后就沒機(jī)會(huì)了,將造成內(nèi)存泄露。
  (3)第三步,分配新的內(nèi)存資源,并復(fù)制字符串。注意函數(shù)strlen返回的是有效字符串長度,不包含結(jié)束符‘\0’。函數(shù)strcpy則連‘\0’一起復(fù)制。
  (4)第四步,返回本對象的引用,目的是為了實(shí)現(xiàn)象 a = b = c 這樣的鏈?zhǔn)奖磉_(dá)。注意不要將 return *this 錯(cuò)寫成 return this 。那么能否寫成return other 呢?效果不是一樣嗎?
  不可以!因?yàn)槲覀儾恢绤?shù)other的生命期。有可能other是個(gè)臨時(shí)對象,在賦值結(jié)束后它馬上消失,那么return other返回的將是垃圾。
  偷懶的辦法處理拷貝構(gòu)造函數(shù)與賦值函數(shù)

  如果我們實(shí)在不想編寫拷貝構(gòu)造函數(shù)和賦值函數(shù),又不允許別人使用編譯器生成的缺省函數(shù),怎么辦?

  偷懶的辦法是:只需將拷貝構(gòu)造函數(shù)和賦值函數(shù)聲明為私有函數(shù),不用編寫代碼。

  例如:
  class A
  { …
  private:
  A(const A &a); // 私有的拷貝構(gòu)造函數(shù)
  A & operate =(const A &a); // 私有的賦值函數(shù)
  };
  如果有人試圖編寫如下程序:
  A b(a); // 調(diào)用了私有的拷貝構(gòu)造函數(shù)
  b = a; // 調(diào)用了私有的賦值函數(shù)
  編譯器將指出錯(cuò)誤,因?yàn)橥饨绮豢梢圆僮鰽的私有函數(shù)。
  3.在編寫派生類的賦值函數(shù)時(shí),注意不要忘記對基類的數(shù)據(jù)成員重新賦值.

回復(fù)

使用道具 舉報(bào)

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表