久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

C++之構(gòu)造函數(shù)

 fisher60 2011-10-13

C++之構(gòu)造函數(shù)  

說明:
從CSDN看到兩篇很好的文章,感覺寫的很好,,特別這幾個(gè)例子舉的好,,轉(zhuǎn)載下來備忘
出處:
http://blog.csdn.net/vagrxie/archive/2007/04/25/1584756.aspx
http://blog.csdn.net/vagrxie/archive/2007/04/27/1587178.aspx
http://blog.csdn.net/vagrxie/archive/2007/04/28/1588984.aspx
作者:九天雁翎
-------------------------------------------------------------------------------------------------------*/
一、構(gòu)造函數(shù)

類多么重要我就不多說了,,只講講學(xué)習(xí),,因?yàn)閭€(gè)人認(rèn)為類的學(xué)習(xí)無論從概念的理解還是實(shí)際代碼的編寫相對其他C兼容向的代碼都是比較有難度的,, 對于以前學(xué)C 的人來說這才是真正的新概念和內(nèi)容,STL其實(shí)還比較好理解,,不就是一個(gè)更大的函數(shù)庫和代碼可以使用嘛,。雖然vector,string就是類,不過我們卻不需要這樣去理解他們,,就可以很好的使用了,。

先說明,1,,這是非常初級(jí)的東西,。2,你懂了就不需要看了,。3,,我寫出來是幫助還不懂得人。4,,我自己也還不太懂,,所以才寫下來,梳理一下,,希望自己能更好的理解,,因?yàn)槲蚁嘈乓痪湓挘芎玫睦斫庖粋€(gè)東西的好方法是把這個(gè)東西教給別人,。有什么不對的地方,,歡迎指出,我非常感謝,,還有很多時(shí)候,,某種方法是不允許的,了解也很重要,,但我不想給出錯(cuò)誤的例子,,那樣很容易給出誤導(dǎo),只講這樣是錯(cuò)誤的,,希望你可以自己輸入去嘗試一下,,看看得出的是什么錯(cuò)誤。

一,、概念:就Bjarne Stroustup自己說,,來自于Simula的概念(The Design and Evolution of C++),我不懂Simula,,所以,,還是對我沒有什么幫助,基本上,都說類是具體對象(實(shí)例)的抽象,,怎么抽象,?就是把一個(gè)實(shí)例的特征拿出來,,比如,,水果是一個(gè)類,蘋果就是一個(gè)實(shí)例,,蘋果有水果的特征,。我們只要從蘋果香蕉中把特征抽象出來“class Fruits{ }”;就好了,。然后 “Fruits apple”,,表示蘋果是一個(gè)水果。就像人是一個(gè)類的話,,我們就都是實(shí)例,。一下也講不清,不過也可以從另一個(gè)角度去理解,,就是Bjarne Stroustup自己說的,,一個(gè)Class其實(shí)就是一個(gè)用戶定義的新Type,這點(diǎn)上和Struct沒有什么本質(zhì)上的區(qū)別,,只是使用上的區(qū)別而已,。之所以沒有把它直接叫作Type是因?yàn)樗囊粋€(gè)不定義新名字的原則。

二,、使用:我一直覺得比較惱火,,光看概念是沒有用的,學(xué)習(xí)程序,,自己編寫代碼是最快的,。下面是幾個(gè)步驟:

1:最簡單的一個(gè)類。

C++中使用任何東西都要先定義吧,,類也不例外,。用水果舉例,水果的特征最起碼的名字先這1個(gè)吧,。名字用string表示,。

例1.0:

#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個(gè)類,名字叫Fruit
{
public:                //標(biāo)號(hào),,表示這個(gè)類成員可以在外部訪問
 string name;         
};
int main()
{
 Fruit apple = {"apple"};  //定義一個(gè)Fruit類對象apple
 cout<< apple.name<<endl;  //使用apple的成員name
 return 0;
}

在這里說明,,以后其他細(xì)節(jié)我都省略說明了,比如#include,using,cout等等,,先去學(xué)會(huì)吧,。我只說類;你會(huì)發(fā)現(xiàn)其實(shí)在這里把class換成struct沒有任何問題,,的確,,而且換成sturct后"public:" 標(biāo)號(hào)都可以省略,,記住,在C++里面,,struct與class其實(shí)沒有本質(zhì)的區(qū)別,,只是stuct默認(rèn)成員為public而class默認(rèn)為private。public顧名思義,,就是公共的,,誰都可以訪問,private自然就是私人的,,別人就不能訪問了,,你把例1.0的public:標(biāo)號(hào)這行去掉試試。你會(huì)得到兩個(gè)錯(cuò)誤,,1,,不能通過 Fruit apple = {"apple"};形式定義,2,,cout<<行不能訪問私有成員,。這里class幾乎就和c里面的struct使用沒有區(qū)別,包括apple.name點(diǎn)操作符表示使用對象apple里面的一個(gè)成員,,還有Fruit apple = {"apple"};這樣的定義初始化方法,。很好理解吧,不多說了,。說點(diǎn)不同的,,C++里面class(struct)不僅可以有數(shù)據(jù)成員,也可以有函數(shù)成員,。比如,,我們希望類Fruit可以自己輸出它的名字,而不是我們從外部訪問成員,。

例1.1:

#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個(gè)類,,名字叫Fruit
{
public:                //標(biāo)號(hào),表示這個(gè)類成員可以在外部訪問
 string name;            //定義一個(gè)name成員         
 void print()              //定義一個(gè)輸出名字的成員print()
 {
  cout<< name<<endl;
 }
};
int main()
{
 Fruit apple = {"apple"};  //定義一個(gè)Fruit類對象apple
 apple.print();  //使用apple的成員print
 return 0;
}

這里你會(huì)發(fā)現(xiàn)與C的不同,,而這看起來一點(diǎn)點(diǎn)地不同,,即可以在class(struct)中添加函數(shù)成員,讓C++有了面向?qū)ο筇卣?,而C只能是結(jié)構(gòu)化編程(這在C剛出來的時(shí)候也是先進(jìn)的代表,,不過卻不代表現(xiàn)在的先進(jìn)編程方法)。還有,,你發(fā)現(xiàn)定義函數(shù)成員和定義普通函數(shù)語法是一樣的,,使用上和普通成員使用也一樣。再進(jìn)一步,在C++中有構(gòu)造函數(shù)的概念,先看例子

例1.2:


#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個(gè)類,,名字叫Fruit
{
public:                //標(biāo)號(hào),,表示這個(gè)類成員可以在外部訪問
 string name;            //定義一個(gè)name成員         
 void print()              //定義一個(gè)輸出名字的成員print()
 {
  cout<< name<<endl;
 }
 Fruit(const string &st)      //定義一個(gè)函數(shù)名等于類名的函數(shù)成員
 {
  name = st;
 }

};
int main()
{
 Fruit apple = Fruit("apple");  //定義一個(gè)Fruit類對象apple
 Fruit orange("orange");
 apple.print();  //使用apple的成員print
 orange.print();   
 return 0;
}

例子1.2里面的函數(shù)名等于類名的函數(shù)成員就叫作構(gòu)造函數(shù),在每次你定義一個(gè)新對象的時(shí)候,,程序自動(dòng)調(diào)用,,這里,定義了2個(gè)對象,,一個(gè)apple, 一個(gè)orange,,分別用了2種不同的方法,你會(huì)發(fā)現(xiàn)構(gòu)造函數(shù)的作用,,這里,要說的是,,假如你還按以前的方法Fruit apple = {"apple"}定義apple你會(huì)編譯失敗,,因?yàn)橛辛藰?gòu)造函數(shù)了,F(xiàn)ruit apple就定義成功了一個(gè)對象,,讓apple對象等于{"apple"}的使用是不允許的,。對象只能等于對象,所以你可以先用Fruit("apple")構(gòu)造一個(gè)臨時(shí)的對象,,然后讓apple等于它,。orange對象的定義就更好理解了,直接調(diào)用構(gòu)造函數(shù)嘛,。這里要說的是,,你不可以直接Fruit banana了,因?yàn)闆]有可以用的構(gòu)造函數(shù),,而沒有用構(gòu)造函數(shù)前,,你是可以這樣做的。直接Fruit apple,,再使apple.name = "apple",,是完全可以的。

例1.3:

#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個(gè)類,,名字叫Fruit
{
public:                //標(biāo)號(hào),,表示這個(gè)類成員可以在外部訪問
 string name;            //定義一個(gè)name成員         
 void print()              //定義一個(gè)輸出名字的成員print()
 {
  cout<< name<<endl;
 }

};
int main()
{
 Fruit apple;  //定義一個(gè)Fruit類對象apple
 apple.name ="apple";  //這時(shí)候才初始化apple的成員name
 apple.print();  //使用apple的成員print
 
 return 0;
}

而有了構(gòu)造函數(shù)以后就不能這樣了,怎么樣不失去這種靈活性呢,?你有兩種辦法,。其一是重載一個(gè)空的構(gòu)造函數(shù),記得,,構(gòu)造函數(shù)也是一個(gè)函數(shù),,自然也可以重載羅。你還不知道什么是重載?那先去學(xué)這個(gè)簡單的東西吧,,類比那家伙復(fù)雜太多了,。

例1.4:

#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個(gè)類,名字叫Fruit
{
public:                //標(biāo)號(hào),,表示這個(gè)類成員可以在外部訪問
 string name;            //定義一個(gè)name成員         
 void print()              //定義一個(gè)輸出名字的成員print()
 {
  cout<< name<<endl;
 }
 Fruit(const string &st)
 {
  name = st;
 }
 Fruit(){}    //重載一個(gè)空構(gòu)造函數(shù)
};
int main()
{
 Fruit apple;  //定義一個(gè)Fruit類對象apple,這時(shí)是允許的了,,自動(dòng)調(diào)用第2個(gè)構(gòu)造函數(shù)
 apple.name ="apple";  //這時(shí)候才初始化apple的成員name
 apple.print();  //使用apple的成員print
 
 return 0;
}

第二種辦法,就是使用構(gòu)造函數(shù)默認(rèn)實(shí)參,;

例1.5

#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個(gè)類,,名字叫Fruit
{
public:                //標(biāo)號(hào),表示這個(gè)類成員可以在外部訪問
 string name;            //定義一個(gè)name成員         
 void print()              //定義一個(gè)輸出名字的成員print()
 {
  cout<< name<<endl;
 }
 Fruit(const string &st = "banana")
 {
  name = st;
 }
};
int main()
{
 Fruit apple;  //定義一個(gè)Fruit類對象apple
 apple.print();
 apple.name ="apple";  //這時(shí)候才初始化apple的成員name
 apple.print();  //使用apple的成員print
 
 return 0;
}

這個(gè)程序里面,,當(dāng)你直接定義一個(gè)無初始化值的apple對象時(shí),,你發(fā)現(xiàn),他直接把name表示為banana,。也許現(xiàn)在你會(huì)問,,為什么需要構(gòu)造函數(shù)呢?這里解釋以前留下來的問題,。即不推介使用Fruit apple = {"apple"}的原因,。因?yàn)檫@樣初始化,你必須要保證成員可以訪問,,當(dāng)name為私有的時(shí)候,,這樣可就不奏效了,為什么需要私有呢,?這就牽涉到類的數(shù)據(jù)封裝問題,,類有不希望別人訪問的成員,以防破壞內(nèi)部的完整性,,也以防誤操作,。這點(diǎn)上要講就很復(fù)雜了,不多講了,。只講操作吧,。

例1.6

#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個(gè)類,名字叫Fruit
{
               //沒有標(biāo)號(hào)了,,表示這個(gè)類成員不可以在外部訪問,,class默認(rèn)為private哦
 string name;            //定義一個(gè)name私有成員         
public: 
 void print()              //定義一個(gè)輸出名字的成員print()
 {
  cout<< name<<endl;
 }
 Fruit(const string &st = "banana")
 {
  name = st;
 }
};
int main()
{
 Fruit banana;  //定義一個(gè)Fruit類對象

 banana.print();
// banana.name ="apple";  //這時(shí)候才改變banana的成員name已經(jīng)是不允許的了
//  你要定義一個(gè)name等于apple的成員必須這樣:
 Fruit apple("apple");
 apple.print();
 
 return 0;
}

要說明的是,構(gòu)造函數(shù)你必須定義成公用的啊,,因?yàn)槟惚仨氁谕獠空{(diào)用啊?,F(xiàn)在講講構(gòu)造函數(shù)特有的形式,初始化列表,,這點(diǎn)和一般的函數(shù)不一樣,。

例1.7:

#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個(gè)類,,名字叫Fruit
{
  string name;            //定義一個(gè)name成員         
public: 
 void print()              //定義一個(gè)輸出名字的成員print()
 {
  cout<< name<<endl;
 }
 Fruit(const string &st = "banana"):name(st){}  //看到不同了嗎?
};
int main()
{
 Fruit banana;  //定義一個(gè)Fruit類對象

 banana.print();
 
 return 0;
}

在參數(shù)表后,,函數(shù)實(shí)體前,,以“:”開頭,列出的一個(gè)列表,,叫初始化列表,,這里初始化列表的作用和以前的例子完全一樣,就是用st初始化name,,問題是,,為什么要特別定義這個(gè)東西呢?C++ Primer的作者Lippman在書里面聲稱這時(shí)許多相當(dāng)有經(jīng)驗(yàn)的C++程序員都沒有掌握的一個(gè)特性,,因?yàn)楹芏鄷r(shí)候根本就不需要,,用我們以前的形式就夠了但有種情況是例外。在說明前我們?yōu)槲覀兊腇ruit加個(gè)固定新成員,,而且定義后不希望再改變了,,比如顏色。

例1.8:

#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個(gè)類,,名字叫Fruit
{
  string name;     //定義一個(gè)name成員         
 const string colour;
public: 
 void print()              //定義一個(gè)輸出名字的成員print()
 {
  cout<<colour<<" "<<name<<endl;
 }
 Fruit(const string &nst = "apple",const string &cst = "green"):name(nst),colour(cst){}
};
int main()
{
 Fruit apple;  //定義一個(gè)Fruit類對象apple
 apple.print();
 
 return 0;
}

在這里你把colour的初始化放到{}里面,用以前的那種方法,,你會(huì)發(fā)現(xiàn)編譯錯(cuò)誤,,因?yàn)樗莄onst的,而實(shí)際上放在{}里面是個(gè)計(jì)算階段,,而放在初始化列表里面就可以,,因?yàn)槌跏蓟斜淼氖褂檬窃跀?shù)據(jù)定義的時(shí)候就自動(dòng)調(diào)用了,因?yàn)檫@個(gè)原因,,數(shù)據(jù)的調(diào)用順序和初始化列表里面的順序無關(guān),,只和數(shù)據(jù)定義的順序有關(guān),給兩個(gè)例子,,比如你在上面的例子中把初始化列表改為":colour(name),name(nst)"沒有任何問題,,因?yàn)樵诙xcolour前面,name 就已經(jīng)定義了,,但是":name(colour),colour(cst)"卻不行,,因?yàn)樵趎ame定義的時(shí)候colour還沒有被定義,而且問題的嚴(yán)重性在于我可以通過編譯.........太嚴(yán)重了,,所以在C++ Primer不推薦你使用數(shù)據(jù)成員初始化另外一個(gè)數(shù)據(jù),,有需要的話,可以":name(cst),colour(cst)",,一樣的效果,。另外,,初始化列表在定義時(shí)就自動(dòng)調(diào)用了,所以在構(gòu)造函數(shù){}之前使用,,你可以看看這個(gè)例子:

例1.9 :

#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個(gè)類,,名字叫Fruit
{
 string name;     //定義一個(gè)name成員         
 const string colour;
public: 
 void print()              //定義一個(gè)輸出名字的成員print()
 {
  cout<<colour<<" "<<name<<endl;
 }
 Fruit(const string &nst = "apple",const string &cst = "green"):name(nst),colour(cst)
 {
 name +="s";    //這時(shí)name已經(jīng)等于"apple“了
 }
};
int main()
{
 Fruit apple("apple","red");  //定義一個(gè)Fruit類對象apple
 apple.print();
 
 return 0;
}

最后輸出red apples。先講到這里吧,,你明白一點(diǎn)什么是類沒有,?像我一樣學(xué)了老半天還不明白的,堅(jiān)持住,,多練習(xí),,總能明白的。我現(xiàn)在似乎明白的多一點(diǎn)了:)

//---------------------------------------------------------------------------------------------------------------
//1看完了,,特別是例1.8不錯(cuò)呀
//還有些郁悶,,對復(fù)制構(gòu)造函數(shù)的體會(huì)不深,于是看了作者的第6篇
//----------------------------------------------------------------------------------------------------------------
二,、復(fù)制構(gòu)造函數(shù)

還記得(1)中講到的構(gòu)造函數(shù)嗎,?復(fù)習(xí)一下,這次我們重載一個(gè)新的默認(rèn)構(gòu)造函數(shù)--即當(dāng)你不給出初始值時(shí)調(diào)用的構(gòu)造函數(shù),,我記得我講過這個(gè)概念吧,,有嗎?看下面的例子,。

例6.0

#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個(gè)類,,名字叫Fruit
{
            
 string name;     //定義一個(gè)name成員          
 string colour;   //定義一個(gè)colour成員
public: 
 void print()              //定義一個(gè)輸出名字的成員print()
 {
  cout<<colour<<" "<<name<<endl;
 }
 Fruit(const string &nst,const string &cst = "green"):name(nst),colour(cst)  //構(gòu)造函數(shù)
 {
 name +="s";
 }
 Fruit(istream &is = cin)   //新的構(gòu)造函數(shù)
 {
  is>>colour>>name;
 }
};
int main()
{
 Fruit apple("apple");  //定義一個(gè)Fruit類對象apple
 Fruit apple2;
 apple.print();
 apple2.print();
  
 return 0;
}

發(fā)現(xiàn)我重載的默認(rèn)構(gòu)造函數(shù)沒有?這次利用的是默認(rèn)形參(istream &is =cin),,學(xué)過io的就應(yīng)該知道,,他的意思表示,默認(rèn)就是從標(biāo)準(zhǔn)設(shè)備輸入(如鍵盤),。你運(yùn)行下,,就知道怎么回事了。現(xiàn)在我們講一個(gè)新內(nèi)容,,復(fù)制構(gòu)造函數(shù),,什么意思?先看下面的例子,。

例6.1:

#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個(gè)類,,名字叫Fruit
{
            
 string name;     //定義一個(gè)name成員          
 string colour;   //定義一個(gè)colour成員
public: 
 void print()              //定義一個(gè)輸出名字的成員print()
 {
  cout<<colour<<" "<<name<<endl;
 }
 Fruit(const string &nst,const string &cst = "green"):name(nst),colour(cst)  //構(gòu)造函數(shù)
 {
 name +="s";
 }
 Fruit(){}
};
int main()
{
 Fruit apple("apple");  //定義一個(gè)Fruit類對象apple
 Fruit apple2(apple);//發(fā)現(xiàn)這里有什么問題沒有?
 apple.print();
 apple2.print();
    return 0;
}

你會(huì)發(fā)現(xiàn)apple2也輸出了green apples,,為什么?。浚╝pple)和("apple")一樣,?你這這樣理解可就錯(cuò)了,,肯定不一樣嘛,。但是當(dāng)我們使用Fruit apple2(apple);的時(shí)候調(diào)用了哪個(gè)構(gòu)造函數(shù)呢?我們沒有定義一個(gè)類似的構(gòu)造函數(shù)???按道理應(yīng)該編譯失敗,不是嗎,?恩,,這里調(diào)用的構(gòu)造函數(shù)就叫 做復(fù)制構(gòu)造函數(shù),即用一個(gè)同樣類型的對象構(gòu)造另一個(gè)對象的構(gòu)造函數(shù),不過在這里,,我們沒有定義,,所以由系統(tǒng)幫我們自動(dòng)定義的,叫做默認(rèn)復(fù)制構(gòu)造函數(shù),。效果 自然就是復(fù)制一下,。你把第一個(gè)對象改成apple3你就會(huì)發(fā)現(xiàn),apple2沒有辦法定義了,,因?yàn)樗{(diào)用的是復(fù)制Fruit對象apple的構(gòu)造函數(shù),,而 不是用字符串"apple"那個(gè)構(gòu)造函數(shù)。C++ Primer這樣定義復(fù)制構(gòu)造函數(shù),,我引用一下“只有單個(gè)形參,,而且該形參是對本類類型對象的引用(常用const修飾)”。我們來看看系統(tǒng)合成的默認(rèn)復(fù) 制構(gòu)造函數(shù)的一個(gè)有趣應(yīng)用:

例6.2:

#include <iostream>
using namespace std;
class Aint
{
public:
 int aival[3];
};
int main()
{
 Aint as={1,2,3};
 cout<<as.aival[0]<<as.aival[1]<<as.aival[2]<<endl;
 Aint bs(as);
 cout<<bs.aival[0]<<bs.aival[1]<<bs.aival[2]<<endl;
 return 0;
}

很簡單的例子吧,,不過也很有趣,,我們都知道,數(shù)組是沒有辦法通過等于來復(fù)制的,,要復(fù)制只能利用循環(huán)遍歷,我們自己定義了一個(gè)只包含整形數(shù)組的類,,而 當(dāng)我們利用系統(tǒng)合成的默認(rèn)復(fù)制構(gòu)造函數(shù)的時(shí)候?qū)崿F(xiàn)了數(shù)組的復(fù)制,,注意,是一次性等于復(fù)制,。呵呵,。這也說明了一個(gè)問題,就是系統(tǒng)的默認(rèn)復(fù)制構(gòu)造函數(shù)在對付數(shù) 組時(shí),,幫我們遍歷復(fù)制了?,F(xiàn)在我們自己定義一個(gè)復(fù)制構(gòu)造函數(shù)。要說明的是,,一般情況下系統(tǒng)定義的復(fù)制構(gòu)造函數(shù)已經(jīng)夠用了,,當(dāng)你自己要定義的時(shí)候是想實(shí)現(xiàn)不 同的功能,比如更好的處理指針的復(fù)制等,,下面的例子只是看看用法,,我也只講用法而不講究有沒有實(shí)際意義,。

例6.3:

#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個(gè)類,名字叫Fruit
{
 string name;     //定義一個(gè)name成員          
 string colour;   //定義一個(gè)colour成員
public:
 void print()              //定義一個(gè)輸出名字的成員print()
 {
  cout<<colour<<" "<<name<<endl;
 }
 Fruit(const string &nst = "apple",const string &cst = "green"):name(nst),colour(cst){}  //構(gòu)造函數(shù)
 Fruit(Fruit &aF):name(aF.name),colour(aF.colour)            //這是我們自己定義的復(fù)制構(gòu)造函數(shù)
 {
  name +="s";                //讓他和默認(rèn)的不同
 }
};

int main()
{
 Fruit apple;  //定義一個(gè)Fruit類對象apple
 Fruit apple2(apple);//調(diào)用的是我們自己定義的復(fù)制構(gòu)造函數(shù)

 apple.print();
 apple2.print();          //你會(huì)發(fā)現(xiàn)輸出多了個(gè)'s'
 return 0;

}

這里你會(huì)看到我們自己定義的復(fù)制構(gòu)造函數(shù)的作用,,直觀的看到apple只輸出green apple,而apple2輸出green aples,,要說明的是,這也是復(fù)制構(gòu)造函數(shù)也是構(gòu)造函數(shù),,也可以用初始化列表,,而且在C++ Primer中還推薦你使用初始化列表。下面我們看看,,假如你向讓你的類禁止復(fù)制怎么辦?。亢芎唵?,讓你的復(fù)制構(gòu)造函數(shù)跑到private里面去,,這時(shí)候 友元和成員還可以使用復(fù)制,那你就光聲明一個(gè)復(fù)制構(gòu)造函數(shù),,但是,,你不定義它,在C++里面,,光聲明不定義一個(gè)成員函數(shù)是合法的,,但是,使用的話就會(huì)導(dǎo)致 編譯失敗了,,(普通函數(shù)也是這樣)通過這種手段,,你就能禁止一切復(fù)制的發(fā)生了(其實(shí)是發(fā)現(xiàn)一切本需要復(fù)制構(gòu)造函數(shù)的地方了)。見下例,。

例6.4:

#include <string>
#include <iostream>
using namespace std;
class Fruit               //定義一個(gè)類,,名字叫Fruit
{
 string name;     //定義一個(gè)name成員          
 string colour;   //定義一個(gè)colour成員
public:
 void print()              //定義一個(gè)輸出名字的成員print()
 {
  cout<<colour<<" "<<name<<endl;
 }
 Fruit(const string &nst = "apple",const string &cst = "green"):name(nst),colour(cst)
 {}  //構(gòu)造函數(shù)
private:
 Fruit(Fruit &aF);        //把它定義在private下
};
int main()
{
 Fruit apple("apple");  //定義一個(gè)Fruit類對象apple
// Fruit apple2(apple);   //你這樣的嘗試會(huì)導(dǎo)致編譯失敗的,cannot access private 錯(cuò)誤  
 apple.print();
 return 0;
}

在犯了一個(gè)我半天也沒有發(fā)現(xiàn)的錯(cuò)誤的后,,我發(fā)現(xiàn)了,,當(dāng)利用形如Fruit apple2 = apple方式來定義并初始化一個(gè)對象的時(shí)候,調(diào)用的也是復(fù)制構(gòu)造函數(shù),,詳情請見那個(gè)帖子《警惕,!C++里面“=”不一定就是等于(賦值)。

//-----------------------------------------------------------------------------------------------------------

//為什么,?

//-----------------------------------------------------------------------------------------------------------

三,、警惕!C++里面“=”不一定就是等于(賦值)


讓我們來現(xiàn)在看一個(gè)這樣的程序:

#include
using namespace std;
class HasPtr
{
public:
int *ptr;
int val;
HasPtr(const int &p,int i):ptr(new int(p)),val(i) { }
HasPtr& operator=(const HasPtr &rhs)
{
 ptr = new int;

*ptr = *rhs.ptr;
val =rhs.val;
return *this;
}
~HasPtr()
{
delete ptr;
}
};

int main()
{
int ival = 5;
HasPtr a(ival,5);
HasPtr b = a;
cout<<*(a.ptr);
return 0;
}

這是看起來是一個(gè)沒有任何問題的程序,,并且在指針的回收處理上非常好,,用的是值型指針來處理類里面的指針,在VC(以后都是指VC++.net 2005)中編譯也可以通過,,在Dev-C++4.9.9.0 中編譯運(yùn)行都沒有問題,。但是在vc中運(yùn)行卻會(huì)出問題,。原因在哪里?經(jīng)我論壇發(fā)帖求教,,是因?yàn)镠asPtr b = a; 語句其實(shí)并不是賦值,,而是調(diào)用了構(gòu)造函數(shù)。不信,?證明如下:

#include <iostream>
using namespace std;
class HasPtr
{
public:
 int *ptr;
 int val;
 HasPtr(const int &p,int i):ptr(new int(p)),val(i) { }
 HasPtr(const HasPtr &orig):ptr(new int(*orig.ptr)),val(orig.val)
 {
 cout<<"Use me(copy constructor)"<<endl;
 }
 HasPtr& operator=(const HasPtr &rhs)
 {
  cout <<"Use me(=)"<<endl; 
  *ptr = *rhs.ptr;
  val =rhs.val;
  return *this;
 }
 ~HasPtr()
 {
  delete ptr;
 }
};

int main()
{
 int ivala = 5;
 HasPtr a(ivala,5);
 HasPtr b = a;
 ivala = 6;
 cout<<*(a.ptr)<<*(b.ptr)<<endl;
 return 0;
}

這一點(diǎn)在VC和在dev-c++中都是一樣的,。你會(huì)發(fā)現(xiàn)調(diào)用的都是copy constructor(復(fù)制構(gòu)造函數(shù)),不過據(jù)說之所以在dev-c++中沒有出錯(cuò),,是因?yàn)榭蓱z的dev-c++檢測能力太差,。。,。,。。,。,。。,。,。。

//------------------------------------------------------------------------------------------------------------------
//看完了,,也轉(zhuǎn)完了,,感謝作者。
//------------------------------------------------------------------------------------------------------------------
四,,對于第三個(gè)問題
在effective c++中,,第0章就有有拷貝構(gòu)造函數(shù)和等于操作符的區(qū)別:
例子:
class Widget
{
    Widget();
    Widget(const& Widget rhs);//拷貝構(gòu)造函數(shù)
    Widget& operator= (const Widget& rhs);//assignment操作符

    Widget w1;
    Widget w2(w1);
    w1 = w2;//調(diào)用=操作符

    Widget w3 = w1;//調(diào)用拷貝構(gòu)造函數(shù)

    //區(qū)別:如果有新對象被定義,一定會(huì)有一個(gè)構(gòu)造函數(shù)
}
是的,,就是這樣,!

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請遵守用戶 評(píng)論公約

    類似文章 更多