青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

學無止境

Step By Step

統計

留言簿

C++ Programmer's Cookbook

外刊IT評論

閱讀排行榜

評論排行榜

【轉】復制構造函數(拷貝構造函數)

轉自此處,貌似博主也是轉別人的

也許很多C++的初學者都知道什么是構造函數,但是對復制構造函數(copy constructor)卻還很陌生。對于我來說,在寫代碼的時候能用得上復制構造函數的機會并不多,不過這并不說明復制構造函數沒什么用,其實復制構造函數能解決一些我們常常會忽略的問題。
       為了說明復制構造函數作用,我先說說我們在編程時會遇到的一些問題。 對于C++中的函數,我們應該很熟悉了,因為平常經常使用;對于類的對象,我們也很熟悉,因為我們也經常寫各種各樣的類,使用各種各樣的對象;對于指針的 操作,我們也不陌生吧?嗯,如果你還不了解上面三個概念的話,我想這篇文章不太適合你,不過看看也無礙^_^。我們經常使用函數,傳遞過各種各樣的參數給 函數,不過把對象(注意是對象,而不是對象的指針或對象的引用)當作參數傳給函數的情況我們應該比較少遇見吧,而且這個對象的構造函數還涉及到一些內存分配的操作。嗯,這樣會有什么問題呢?
       把參數傳遞給函數有三種方法,一種是值傳遞,一種是傳地址,還有一種 是傳引用。前者與后兩者不同的地方在于:當使用值傳遞的時候,會在函數里面生成傳遞參數的一個副本,這個副本的內容是按位從原始參數那里復制過來的,兩者 的內容是相同的。當原始參數是一個類的對象時,它也會產生一個對象的副本,不過在這里要注意。一般對象產生時都會觸發構造函數的執行,但是在產生對象的副 本時卻不會這樣,這時執行的是對象的復制構造函數。為什么會這樣?嗯,一般的構造函數都是會完成一些成員屬性初始化的工作,在對象傳遞給某一函數之前,對 象的一些屬性可能已經被改變了,如果在產生對象副本的時候再執行對象的構造函數,那么這個對象的屬性又再恢復到原始狀態,這并不是我們想要的。所以在產生對象副本的時候,構造函數不會被執行,被執行的是一個默認的構造函數。當函數執行完畢要返回的時候,對象副本會執行析構函數, 如果你的析構函數是空的話, 就不會發生什么問題,但一般的析構函數都是要完成一些清理工作,如釋放指針所指向的內存空間。這時候問題就可能要出現了。假如你在構造函數里面為一個指針 變量分配了內存,在析構函數里面釋放分配給這個指針所指向的內存空間,那么在把對象傳遞給函數至函數結束返回這一過程會發生什么事情呢?首先有一個對象的 副本產生了,這個副本也有一個指針,它和原始對象的指針是指向同塊內存空間的。函數返回時,對象的析構函數被執行了,即釋放了對象副本里面指針所指向的內 存空間,但是這個內存空間對原始對象還是有用的啊,就程序本身而言,這是一個嚴重的錯誤。然而錯誤還沒結束,當原始對象也被銷毀的時候,析構函數再次執 行,對同一塊系統動態分配的內存空間釋放兩次是一個未知的操作,將會產生嚴重的錯誤。
       上面說的就是我們會遇到的問題。解決問題的方法是什么呢?首先我們想 到的是不要以傳值的方式來傳遞參數,我們可以用傳地址或傳引用。沒錯,這樣的確可以避免上面的情況,而且在允許的情況下,傳地址或傳引用是最好的方法,但 這并不適合所有的情況,有時我們不希望在函數里面的一些操作會影響到函數外部的變量。那要怎么辦呢?可以利用復制構造函數來解決這一問題。復制構造函數就是在產生對象副本的時候執行的,我們可以定義自己的復制構造函數。在復制構造函數里面我們申請一個新的內存空間來保存構造函數里面的那個指針所指向的內容。這樣在執行對象副本的析構函數時,釋放的就是復制構造函數里面所申請的那個內存空間。
       除了將對象傳遞給函數時會存在以上問題,還有一種情況也會存在以上問題,就是當函數返回對象時,會產生一個臨時對象,這個臨時對象和對象的副本性質差不多。
拷貝構造函數,經常被稱作X(X&),是一種特殊的構造函數,他由編譯器調用來完成一些基于同一類的其他對象的構件及初始化。它的唯一的一個參數(對象的引用)是不可變的(因為是const型的)。這個函數經常用在函數調用期間于用戶定義類型的值傳遞及返回。拷貝構造函數要調用基類的拷貝構造函數和成員函數。如果可以的話,它將用常量方式調用,另外,也可以用非常量方式調用。
在C++中,下面三種對象需要拷貝的情況。因此,拷貝構造函數將會被調用。
1). 一個對象以值傳遞的方式傳入函數體
2). 一個對象以值傳遞的方式從函數返回
3). 一個對象需要通過另外一個對象進行初始化
以 上的情況需要拷貝構造函數的調用。如果在前兩種情況不使用拷貝構造函數的時候,就會導致一個指針指向已經被刪除的內存空間。對于第三種情況來說,初始化和賦值的不同含義是構造函數調用的原因。事實上,拷貝構造函數是由普通構造函數和賦值操作符共同實現的。描述拷貝構造函數和賦值運算符的異同的參考資料有很多。
拷貝構造函數不可以改變它所引用的對象,其原因如下:當一個對象以傳遞值的方式傳一個函數的時候,拷貝構造函數自動的被調用來生成函數中的對象。如果一個對象是被傳入自己的拷貝構造函數,它的拷貝構造函數將會被調用來拷貝這個對象這樣復制才可以傳入它自己的拷貝構造函數,這會導致無限循 環。
除了當對象傳入函數的時候被隱式調用以外,拷貝構造函數在對象被函數返回的時候也同樣的被調用。換句話說,你從函數返回得到的只是對象的一份拷貝。但是同樣的,拷貝構造函數被正確的調用了,你不必擔心。
如果在類中沒有顯式的聲明一個拷貝構造函數,那么,編譯器會私下里為你制定一個函數來進行對象之間的位拷貝(bitwise copy)。這個隱含的拷貝構造函數簡單的關聯了所有的類成員。許多作者都會提及這個默認的拷貝構造函數。注意到這個隱式的拷貝構造函數和顯式聲明的拷貝構造函數的不同在于對于成員的關聯方式。顯式聲明的拷貝構造函數關聯的只是被實例化的類成員的缺省構造函數除非另外一個構造函數在類初始化或者在構造列表的時候被調用。
拷貝構造函數使程序更加有效率,因為它不用再構造一個對象的時候改變構造函數的參數列表。設計拷貝構造函數是一個良好的風格,即使是編譯系統提供的幫助你申請內存默認拷貝構造函數。事實上,默認拷貝構造函數可以應付許多情況。
附另外一篇關于復制構造函數的文章:

對一個簡單變量的初始化方法是用一個常量或變量初始化另一個變量,例如:

int m = 80
int n = m;

  我們已經會用構造函數初始化對象,那么我們能不能象簡單變量的初始化一樣,直接用一個對象來初始化另一個對象呢?答案是肯定的。我們以前面定義的Point類為例:
Point pt1(1525);
Point pt2 
= pt1;

后一個語句也可以寫成:
Point pt2( pt1);

它 是用pt1初始化pt2,此時,pt2各個成員的值與pt1各個成員的值相同,也就是說,pt1各個成員的值被復制到pt2相應的成員當中。在這個初始化 過程當中,實際上調用了一個復制構造函數。當我們沒有顯式定義一個復制構造函數時,編譯器會隱式定義一個缺省的復制構造函數,它是一個內聯的、公有的成 員,它具有下面的原型形式:
Point:: Point (const Point &);

可見,復制構造函數與構造函數的不同之處在于形參,前者的形參是Point對象的引用,其功能是將一個對象的每一個成員復制到另一個對象對應的成員當中。
  雖然沒有必要,我們也可以為Point類顯式定義一個復制構造函數:
Point:: Point (const Point &pt)
{
  xVal
=pt. xVal;
  yVal
=pt. yVal;

如果一個類中有指針成員,使用缺省的復制構造函數初始化對象就會出現問題。為了說明存在的問題,我們假定對象A與對象B是相同的類,有一個指針成員,指 向對象C。當用對象B初始化對象A時,缺省的復制構造函數將B中每一個成員的值復制到A的對應的成員當中,但并沒有復制對象C。也就是說,對象A和對象B 中的指針成員均指向對象C,實際上,我們希望對象C也被復制,得到C的對象副本D。否則,當對象A和B銷毀時,會對對象C的內存區重復釋放,而導致錯誤。 為了使對象C也被復制,就必須顯式定義復制構造函數。下面我們以string類為例說明,如何定義這個復制構造函數。

例題
例10-11
 
 1 class String
 2 {
 3  public:
 4   String(); //構造函數
 5   String(const String &s); //復制構造函數
 6   ~String(); //析構函數
 7 
 8   // 接口函數
 9   void set(char const *data);
10   char const *get(void);
11 
12  private:
13   char *str; //數據成員ptr指向分配的字符串
14 };
15 String ::String(const String &s)
16 {
17  str = new char[strlen(s.str) + 1];
18  strcpy(str, s.str);
19 }

我們也常用無名對象初始化另一個對象,例如:

Point pt = Point(1020);

  類名直接調用構造函數就生成了一個無名對象,上式用左邊的無名對象初始化右邊的pt對象。
  構造函數被調用通常發生在以下三種情況,第一種情況就是我們上面看到的:用一個對象初始化另一個對象時;第二種情況是當對象作函數參數,實參傳給形參時;第三種情況是程序運行過程中創建其它臨時對象時。下面我們再舉一個例子,就第二種情況和第三種情況進行說明:
Point foo(Point pt)
  {
   …
   
return pt;
  }
  
void main()
  {
   Point pt1 
= Point(1020);
   Point pt2;
   …
   pt2
=foo(pt);
   …
  }

  在main函數中調用foo函數時,實參pt傳給形參pt,將實參pt復制給形參pt,要調用復制構造函數,當函數foo返回時,要創建一個pt的臨時對象,此時也要調用復制構造函數。

 

缺省的復制構造函數
  在類的定義中,如果沒有顯式定義復制構造函數,C++編譯器會自動地定義一個缺省的復制構造函數。下面是使用復制構造函數的一個例子:

例題
例10-12
 
 1 #include <iostream.h>
 2 #include <string.h>
 3 class withCC
 4 {
 5  public:
 6  withCC(){}
 7  withCC(const withCC&)
 8  {
 9   cout<<"withCC(withCC&)"<<endl;
10  }
11 };
12 
13 class woCC
14 {
15  enum{bsz = 100};
16  char buf[bsz];
17 public:
18  woCC(const char* msg = 0)
19  {
20   memset(buf, 0, bsz);
21   if(msg) strncpy(buf, msg, bsz);
22  }
23  void print(const char* msg = 0)const
24  {
25   if(msg) cout<<msg<<":";
26   cout<<buf<<endl;
27  }
28 };
29 
30 class composite
31 {
32  withCC WITHCC;
33  woCC WOCC;
34 public:
35  composite() : WOCC("composite()"){}
36  void print(const char* msg = 0)
37  {
38   WOCC.print(msg);
39  }
40 };
41 
42 void main()
43 {
44  composite c;
45  c.print("contents of c");
46  cout<<"calling composite copy-constructor"<<endl;
47  composite c2 = c;
48  c2.print("contents of c2");
49 

類withCC有一個復制構造函數,類woCC和類composite都沒有顯式定義復制構造函數。如果在類中沒有顯式定義復制構造函數,則編譯器將自動地創建一個缺省的構造函數。不過在這種情況下,這個構造函數什么也不作。
  類composite既含有withCC類的成員對象又含有woCC類的成員對象,它使用無參的構造函數創建withCC類的對象WITHCC(注意內嵌的對象WOCC的初始化方法)。
  在main()函數中,語句:
  composite c2 = c;
通過對象C初始化對象c2,缺省的復制構造函數被調用。
  最好的方法是創建自己的復制構造函數而不要指望編譯器創建,這樣就能保證程序在我們自己的控制之下。

posted on 2010-04-14 11:03 wstonep 閱讀(259) 評論(0)  編輯 收藏 引用

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲精品自在久久| 国产精品成人一区二区艾草| 国内外成人在线| 久久经典综合| 久久精品国产2020观看福利| 国产一级揄自揄精品视频| 欧美在线综合| 久久精品日韩一区二区三区| 在线免费高清一区二区三区| 亚洲风情亚aⅴ在线发布| 久久美女性网| 亚洲乱码国产乱码精品精可以看 | 国产精品成人在线| 久久精品女人| 久久野战av| 中文在线不卡| 欧美在线看片a免费观看| 伊人婷婷欧美激情| 亚洲精品日本| 国产三级欧美三级日产三级99| 久久久久久999| 欧美高清在线视频| 亚久久调教视频| 老司机精品视频一区二区三区| 一本色道久久综合亚洲精品婷婷 | 亚洲欧洲日本国产| 中文网丁香综合网| 伊人天天综合| 亚洲午夜精品久久| 亚洲日本欧美日韩高观看| 一本色道久久加勒比精品| 红桃视频欧美| 在线亚洲观看| 亚洲六月丁香色婷婷综合久久| 亚洲欧美日韩在线| 一区二区av在线| 久久高清福利视频| 亚洲欧美视频一区二区三区| 欧美成人精品激情在线观看| 欧美亚洲一区二区三区| 欧美激情在线观看| 蜜臀av性久久久久蜜臀aⅴ四虎| 国产精品第三页| 欧美国产亚洲精品久久久8v| 国产亚洲精品高潮| 一本久道久久综合婷婷鲸鱼| 亚洲欧洲三级| 久久久蜜桃精品| 久久国产66| 国产精品久久久久毛片软件| 亚洲人成小说网站色在线| 亚洲第一天堂无码专区| 欧美一区二区三区视频| 亚洲欧美中文在线视频| 欧美日精品一区视频| 亚洲国产va精品久久久不卡综合| 国产日韩欧美一区二区| 亚洲一区二区视频在线| 亚洲在线视频| 欧美午夜在线| 亚洲一区二区精品| 亚洲一区在线免费观看| 欧美日本在线播放| 亚洲免费激情| 一区二区三区.www| 欧美视频在线观看免费网址| 99精品国产在热久久| 中文一区字幕| 国产精品高潮呻吟久久av黑人| 夜夜嗨一区二区三区| 亚洲视频欧洲视频| 国产精品久久久久久久第一福利| 日韩午夜在线电影| 亚洲一区久久久| 国产精品日韩欧美一区| 午夜精品美女久久久久av福利| 欧美一级专区| 韩曰欧美视频免费观看| 久久精品导航| 亚洲国语精品自产拍在线观看| 亚洲每日在线| 国产精品yjizz| 亚洲综合三区| 裸体歌舞表演一区二区| 亚洲欧洲一区二区三区在线观看| 欧美国内亚洲| 在线亚洲一区二区| 久久久久久久一区二区| 亚洲第一狼人社区| 欧美视频福利| 久久本道综合色狠狠五月| 欧美成人有码| 亚洲与欧洲av电影| 久久精品男女| 亚洲国产精品v| 午夜精品一区二区三区四区| 狠狠色狠狠色综合日日五| 免费观看成人| av成人免费在线观看| 久久久精品久久久久| 亚洲精品在线观| 国产精品视频一二三| 狼人社综合社区| 亚洲一区二区精品在线| 欧美成人三级在线| 欧美亚洲一级| 日韩视频在线观看免费| 国内精品国语自产拍在线观看| 欧美mv日韩mv国产网站app| 亚洲一区二区三区在线视频| 欧美大片在线观看一区| 性欧美暴力猛交另类hd| 亚洲精品在线一区二区| 国产一区二区三区久久悠悠色av| 欧美极品aⅴ影院| 久久久五月婷婷| 亚洲免费小视频| 亚洲毛片一区二区| 欧美激情免费在线| 久久久午夜视频| 午夜精品影院| 正在播放亚洲| 亚洲激情av在线| 国产在线精品一区二区中文| 欧美日韩综合| 欧美日韩国产黄| 久久亚洲欧美| 亚洲欧美日韩一区二区在线| 一区二区三区精品| 亚洲精品美女在线观看播放| 欧美jizzhd精品欧美巨大免费| 久久精品青青大伊人av| 午夜精品久久久久久久男人的天堂 | 亚洲欧美在线网| 99国产精品视频免费观看| 欧美顶级少妇做爰| 欧美高清在线观看| 免费久久99精品国产| 久久久亚洲国产美女国产盗摄| 欧美一区二区三区男人的天堂| 亚洲一区二区精品视频| 一本色道久久综合亚洲精品高清| 亚洲老司机av| 亚洲精品资源美女情侣酒店| 亚洲区一区二| 亚洲清纯自拍| 一本久道久久久| 亚洲一区二区三区免费在线观看| 这里只有精品电影| 亚洲一区一卡| 欧美一区二区三区精品电影| 欧美在线观看视频一区二区| 欧美伊人久久| 久久久久久久久伊人| 久久三级福利| 欧美黑人一区二区三区| 亚洲高清视频的网址| 亚洲韩国一区二区三区| 亚洲精品乱码久久久久久日本蜜臀| 亚洲精品小视频| 99re66热这里只有精品3直播 | 亚洲国产成人久久综合| 亚洲精品国产精品国产自| 一本一本久久a久久精品综合麻豆| 亚洲精品午夜精品| 亚洲欧美视频在线| 亚洲电影免费观看高清完整版| 亚洲国产你懂的| 日韩视频免费观看高清完整版| 宅男精品导航| 欧美影院精品一区| 欧美成人午夜影院| 国产精品美腿一区在线看 | 国产欧美一区二区三区沐欲| 国产在线视频不卡二| 亚洲人体偷拍| 欧美一级在线播放| 亚洲国产精品久久久久秋霞蜜臀| 亚洲午夜一二三区视频| 久久久久久一区二区三区| 欧美区视频在线观看| 国产乱码精品一区二区三区五月婷 | 日韩午夜在线电影| 欧美在线观看日本一区| 欧美激情一区二区三区蜜桃视频| 99re成人精品视频| 久久久精品一区| 欧美日韩国产探花| 在线观看日韩www视频免费| 亚洲午夜一二三区视频| 久久资源在线| 亚洲无线视频| 欧美成人自拍视频| 国语自产精品视频在线看一大j8| av成人动漫| 欧美大片一区二区| 欧美自拍偷拍午夜视频| 国产精品大片免费观看| 亚洲每日在线| 欧美成人中文|