拷贝构造函数和赋值函数的一些知识
/*******************拷貝構(gòu)造函數(shù)和賦值運(yùn)算符重載有以下兩個(gè)不同之處***************************/
?
1.拷貝構(gòu)造函數(shù)生成新的類對象,而賦值運(yùn)算符不能。
2.由于拷貝構(gòu)造函數(shù)是直接構(gòu)造一個(gè)新的類對象,所以在初始化這個(gè)對象之前不用檢驗(yàn)源對象是否和新對象相同,而復(fù)制操作符需要這個(gè)操作,另外賦值運(yùn)算符中如果原來對象中有內(nèi)存分配,要先把內(nèi)存釋放掉。
下面是String類的一個(gè)實(shí)現(xiàn)的部分函數(shù),可以看出二者的區(qū)別。
1 class String{ 2 public: 3 String(const char * str = NULL); 4 String(const String& other); 5 ~String(); 6 String& operator=(const String& other); 7 private: 8 char *m_data; 9 }; 10 11 String::String(const char * str){ 12 if (str != NULL){ 13 int length = strlen(str); 14 m_data = new char[length + 1]; 15 strcpy(m_data, str); 16 } 17 } 18 19 String::~String(){ 20 delete m_data; 21 } 22 23 String::String(const String& other){ 24 int length = strlen(other.m_data); 25 m_data = new char[length + 1]; 26 assert(m_data != NULL); 27 strcpy(m_data, other.m_data); 28 } 29 30 String& String::operator=(const String& other){ 31 if (this == &other){ //這里要判斷是否自我賦值 32 return *this; 33 } 34 if (m_data != NULL){ //要檢驗(yàn)是否有內(nèi)存分配 35 delete m_data; 36 } 37 int length = strlen(other.m_data); 38 m_data = new char[length + 1]; 39 assert(m_data == NULL); 40 strcpy(m_data, other.m_data); 41 return *this; 42 }
?
/**************一種調(diào)用拷貝構(gòu)造函數(shù)和賦值函數(shù)的微妙差別*******************/
?
#include<iostream> #include<assert.h> using namespace std;class B{ public:B():data(0){cout << "default constructor" << endl;}B(int i):data(i){cout << "constructed by parameter " << data << endl;}B (B &b){data = b.data;cout << "copyed by parameter " << data << endl;}B & operator=(const B& b){this->data = b.data;cout << "= by parameter " << data << endl;return *this;} private:int data; };
void test(){
?? ?B b1;
?? ?B b2 = b1;
?? ?B b3;
?? ?b3 = b1;
}int main(){
test();system("pause");return 0; }
test()函數(shù)和system("pause")是為了不退出main函數(shù),可以看到析構(gòu)函數(shù)執(zhí)行。運(yùn)行之后得到以下結(jié)果。
default constructor
copyed by parameter 0
default constructor
=???? by parameter 0
注意仔細(xì)看test函數(shù)里的代碼段。
b2調(diào)用的是拷貝構(gòu)造函數(shù),而b3調(diào)用的是賦值函數(shù)。這兩者是不同的。
?
/*********************關(guān)于拷貝構(gòu)造函數(shù)和賦值函數(shù)的臨時(shí)對象問題******************************/
?
看以下代碼,它的輸出會是什么。
1 #include<iostream> 2 #include<assert.h> 3 using namespace std; 4 5 class B{ 6 public: 7 B():data(0){ 8 cout << "default constructor" << endl; 9 } 10 ~B(){ 11 cout << "destructed by parameter " << data << endl; 12 } 13 B(int i):data(i){ 14 cout << "constructed by parameter " << data << endl; 15 } 16 B (B &b){ 17 data = b.data; 18 cout << "copyed by parameter " << data << endl; 19 } 20 B & operator=(const B& b){ 21 this->data = b.data; 22 cout << "= by parameter " << data << endl; 23 return *this; 24 } 25 private: 26 int data; 27 }; 28 29 B play(B b){ 30 return b; 31 } 32 33 void test(){ 34 play(1); 35 B t1 = play(2); 36 B t2; 37 t2 = play(3); 38 } 39 40 int main(){ 41 42 test(); 43 system("pause"); 44 return 0; 45 }
這個(gè)程序比上一個(gè)增加了一個(gè)play()函數(shù)和析構(gòu)函數(shù)的輸出。看到輸出結(jié)果后,有一些疑惑。以下為輸出結(jié)果,為方便起見,給它們編號。
(1)constructed by parameter 1????????????????????????????????????????????
(2)copyed by parameter 1
(3)destructed by parameter 1
(4)destructed by parameter 1
(5)constructed by parameter 2
(6)copyed by parameter 2
(7)destructed by parameter 2
(8)default constructor
(9)constructed by parameter 3
(10)copyed by parameter 3
(11)destructed by parameter 3
(12)=???? by parameter 3
(13)destructed by parameter 3
(14)destructed by parameter 3
(15)destructed by parameter 2
如果有疑問,可以先了解下面三點(diǎn)。
?
1.用同一個(gè)類的源對象構(gòu)造一個(gè)目標(biāo)對象是,會調(diào)用拷貝構(gòu)造函數(shù)來構(gòu)造目標(biāo)對象,如果沒有定義拷貝構(gòu)造函數(shù),將會調(diào)用默認(rèn)的拷貝函數(shù)來構(gòu)造目標(biāo)對象。
2.當(dāng)類有一個(gè)帶有一個(gè)參數(shù)的構(gòu)造函數(shù)時(shí),可以用這個(gè)參數(shù)同類型的數(shù)據(jù)初始化這個(gè)對象,默認(rèn)會調(diào)用這個(gè)構(gòu)造函數(shù)。
3.當(dāng)一個(gè)函數(shù)的返回值為一個(gè)類的對象時(shí),如果在調(diào)用函數(shù)中(注意是調(diào)用函數(shù),不是被調(diào)用函數(shù)),沒有定義一個(gè)對象來接收這個(gè)返回值,會用返回一個(gè)臨時(shí)對象保存返回對象的值。在被調(diào)用函數(shù)(注意是被調(diào)用函數(shù))結(jié)束時(shí),這個(gè)臨時(shí)對象被銷毀。而當(dāng)有一個(gè)接收對象時(shí),就將返回對象賦值給接收對象,這個(gè)返回對象在調(diào)用函數(shù)(注意是調(diào)用函數(shù))結(jié)束時(shí)調(diào)用析構(gòu)函數(shù)。
?
第一點(diǎn)體現(xiàn)在程序35行,上面講過,這是會調(diào)用拷貝構(gòu)造函數(shù)而不是賦值函數(shù)。
第二點(diǎn)體現(xiàn)在34行,play(1)的類型是整型,而類B中有一個(gè)帶int類型的構(gòu)造函數(shù),當(dāng)實(shí)參1傳給形參b,會調(diào)用這個(gè)構(gòu)造函數(shù)。
第三點(diǎn)體現(xiàn)在34行和37行。play(1)函數(shù)被調(diào)用,返回一個(gè)類對象,而此時(shí)沒有對象接收(在左邊接受賦值),所以會返回一個(gè)臨時(shí)對象,而這個(gè)臨時(shí)對象在被調(diào)用函數(shù)play結(jié)束時(shí)調(diào)用析構(gòu)函數(shù)銷毀,輸出(4)destructed by parameter 1;t2 = play(3);語句中play(3)被調(diào)用,返回一個(gè)對象,而此時(shí)有對象(t2)接收,所以調(diào)用賦值函數(shù)賦值給t2,在調(diào)用函數(shù)(test)結(jié)束時(shí),這個(gè)對象才被銷毀輸出(13)destructed by parameter 3。
?
所以,上面的輸出的含義分別是:
constructed by parameter 1????????????????? //用1構(gòu)造參數(shù)b
copyed by parameter 1??????????????????????? //用b構(gòu)造一個(gè)臨時(shí)對象
destructed by parameter 1?????????????????? //參數(shù)b被析構(gòu)
destructed by parameter 1?????????????????? //臨時(shí)對象被析構(gòu)
constructed by parameter 2???????????????? //用2構(gòu)造參數(shù)b
copyed by parameter 2??????????????????????? //用b構(gòu)造t1
destructed by parameter 2?????????????????? //參數(shù)b被析構(gòu)
default constructor?????????????????????????? ? //構(gòu)造t2
constructed by parameter 3????????????? ?? //用3構(gòu)造參數(shù)b
copyed by parameter 3?????????????????????? //用b拷貝一個(gè)臨時(shí)對象
destructed by parameter 3??????????????? ? //參數(shù)b被析構(gòu)
=???? by parameter 3?????????????????????? ? ? //調(diào)用賦值函數(shù)=()初始化t2
destructed by parameter 3????????????? ?? //臨時(shí)對象被析構(gòu)
destructed by parameter 3?????????????? ? //t2被析構(gòu)
destructed by parameter 2????????????? ?? //t1被析構(gòu)
轉(zhuǎn)載于:https://www.cnblogs.com/piginthetree/p/3898487.html
總結(jié)
以上是生活随笔為你收集整理的拷贝构造函数和赋值函数的一些知识的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JS下计算当前日期(当天)后N天出现NA
- 下一篇: 史上最浅显易懂的Git教程!