C++之拷贝函数
拷貝構(gòu)造函數(shù)是一種特殊的構(gòu)造函數(shù),函數(shù)的名稱必須和類名稱一致,它的唯一的一個參數(shù)是本類型的一個引用變量,該參數(shù)是const類型,不可變的。例如:類X的拷貝構(gòu)造函數(shù)的形式為X(X& x)。
以下情況都會調(diào)用拷貝構(gòu)造函數(shù):
一個對象以值傳遞的方式傳入函數(shù)體
一個對象以值傳遞的方式從函數(shù)返回
一個對象需要通過另外一個對象進行初始化。
如果在類中沒有顯式地聲明一個拷貝構(gòu)造函數(shù),那么,編譯器將會自動生成一個默認的拷貝構(gòu)造函數(shù),該構(gòu)造函數(shù)完成對象之間的位拷貝。位拷貝又稱淺拷貝,后面將進行說明。
自定義拷貝構(gòu)造函數(shù)是一種良好的編程風格,它可以阻止編譯器形成默認的拷貝構(gòu)造函數(shù),提高源碼效率。
淺拷貝和深拷貝
在某些狀況下,類內(nèi)成員變量需要動態(tài)開辟堆內(nèi)存,如果實行位拷貝,也就是把對象里的值完全復制給另一個對象,如A=B。這時,如果B中有一個成員變量指針已經(jīng)申請了內(nèi)存,那A中的那個成員變量也指向同一塊內(nèi)存。這就出現(xiàn)了問題:當B把內(nèi)存釋放了(如:析構(gòu)),這時A內(nèi)的指針就是野指針了,出現(xiàn)運行錯誤。
深拷貝和淺拷貝可以簡單理解為:如果一個類擁有資源,當這個類的對象發(fā)生復制過程的時候,資源重新分配,這個過程就是深拷貝,反之,沒有重新分配資源,就是淺拷貝。
深拷貝和淺拷貝的定義可以簡單理解成:如果一個類擁有資源(堆,或者是其它系統(tǒng)資源),當這個類的對象發(fā)生復制過程的時候,這個過程就可以叫做深拷貝,反之對象存在資源,但復制過程并未復制資源的情況視為淺拷貝。
淺拷貝資源后在釋放資源的時候會產(chǎn)生資源歸屬不清的情況導致程序運行出錯。
代碼實現(xiàn):
拷貝構(gòu)造:
默認構(gòu)造函數(shù):
#include <stdio.h>class Test7_1 { public:Test7_1(){}Test7_1(int a){m_a = a;}void print (){printf ("m_a = %d\n", m_a);} private:int m_a; };// 如果類中沒有定義任何構(gòu)造函數(shù),編譯器會自動生成一個無參構(gòu)造函數(shù),沒有做任何事情 // 如果寫了構(gòu)造函數(shù),編譯器將不再提供默認的無參構(gòu)造函數(shù) // 如果還想進行無參構(gòu)造,需要顯示定義無參構(gòu)造函數(shù)// 如果沒有定義拷貝構(gòu)造函數(shù),編譯器會自動生成一個拷貝構(gòu)造函數(shù), // 會做普通類型數(shù)據(jù)的復制// 還會生成一個默認的 析構(gòu)函數(shù) class Test7_2 { #if 0Test7_2() {}Test7_2(const Test7_2 &obj) {}~Test7_2(){}; #endif };int main7_1() {Test7_1 b;Test7_1 a(10);Test7_1 c = a;a.print();c.print();return 0; }深拷貝和淺拷貝:
#include <stdio.h> #include <string.h> #include <stdlib.h>// 淺拷貝:在拷貝指針的時候只是拷貝了地址,不會進行空間的復制 class Test8_1 { public:Test8_1(int id, char *name){m_id = id;m_name = (char *)malloc(sizeof(char)*20);strcpy (m_name, name);}~Test8_1(){if (m_name != NULL){free (m_name);m_name = NULL;}printf ("析構(gòu)被調(diào)用**********\n");}void print(){printf ("id = %d, name = %s\n", m_id, m_name);} private:int m_id; // char m_name[20];char *m_name; };// 深拷貝 class Test8_2 { public:Test8_2(int id, char *name){m_id = id;m_name = (char *)malloc(sizeof(char)*20);strcpy (m_name, name);}// 自己寫拷貝構(gòu)造函數(shù),避免淺拷貝Test8_2(const Test8_2 &obj){m_id = obj.m_id;m_name = (char *)malloc(sizeof(char)*20);strcpy (m_name, obj.m_name);}~Test8_2(){if (m_name != NULL){free (m_name);m_name = NULL;}printf ("析構(gòu)被調(diào)用**********\n");}void print(){printf ("id = %d, name = %s\n", m_id, m_name);} private:int m_id;char *m_name; };class Test8_3 { private:// 將拷貝構(gòu)造寫成私有的函數(shù),只需聲明,不需要實現(xiàn)Test8_3(const Test8_3 &ibj);public:Test8_3(int a){m_a = a;}private:int m_a; }; int main8_3() {Test8_3 t(10);// Test8_3 t1 = t;return 0; }int main8_2() {Test8_2 t1(10, "wang");t1.print();// 調(diào)用自己寫的拷貝構(gòu)造函數(shù),進行深拷貝Test8_2 t2 = t1;t2.print();return 0; }int main8_1() {Test8_1 t1(10, "wang");t1.print();// 調(diào)用默認的拷貝構(gòu)造函數(shù)Test8_1 t2 = t1;//t2.print();return 0; }總結(jié)
- 上一篇: odciexttableopen 调用出
- 下一篇: 基于java的数据结构学习——动态数组C