构造函数和析构函数深拷贝和浅拷贝
在C++中能夠定義和使用和類名相同的成員函數(shù),這種和類名相同的成員函數(shù)叫做構(gòu)造函數(shù)
構(gòu)造函數(shù)可以有參數(shù)還可以沒有參數(shù)
構(gòu)造函數(shù)沒有返回類型的聲明
一般情況下C++編譯器會自動調(diào)用構(gòu)造函數(shù)
當然也可以手動的去調(diào)用構(gòu)造函數(shù)
C++中的類也可以定義一個特殊的成員函數(shù)清理對象,這個特殊的成員函數(shù)叫做析構(gòu)函數(shù)語法: ~className()
析構(gòu)函數(shù)沒有參數(shù)也沒有任何返回類型的聲明
析構(gòu)函數(shù)在對象銷毀之前被調(diào)用
析構(gòu)函數(shù)的調(diào)用機制,C++編譯器自動調(diào)用
構(gòu)造函數(shù)也是成員函數(shù)只不過是一種特殊的成員函數(shù)
、
構(gòu)造函數(shù)和析構(gòu)函數(shù)的作用
通過結(jié)果可以看出來構(gòu)造函數(shù)和析構(gòu)函數(shù)的執(zhí)行過程是構(gòu)造函數(shù)和聲明的順序相同,析構(gòu)函數(shù)和聲明的順序相反。
#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std;class Test { public:Test() //構(gòu)造函數(shù){p = (char *) malloc(100); a =10;strcpy(p ,"aaaaaaaddjdjj");cout << "這是一個構(gòu)造函數(shù)" << endl;}void printP(){cout << p << endl;cout << a << endl;}~Test(){if ( p != NULL){free(p);}cout << "這是一個析構(gòu)函數(shù)" << endl;} protected: private:int a;char *p; };//給對象搭建一個舞臺研究對象的行為 void objPlay() {Test c1;c1.printP();cout << "分隔符" << endl;Test c2;c2.printP(); } int main() {objPlay();cout << "hello world!" << endl;system("pause");return 0; }匿名構(gòu)造函數(shù)
#include <iostream> using namespace std;class Location { public:Location( int xx = 0 , int yy = 0 ) { X = xx ; Y = yy ; cout << "Constructor Object.\n" ; }//copy構(gòu)造函數(shù) 完成對象的初始化Location(const Location & obj) //copy構(gòu)造函數(shù) {X = obj.X; Y = obj.Y;}~Location() { cout << X << "," << Y << " Object destroyed." << endl ; }int GetX () { return X ; } int GetY () { return Y ; } private : int X , Y ; } ; // g函數(shù)返回一個元素 //你這么寫代碼,設(shè)計編譯器的大牛們: //我就給你返回一個新對象(沒有名字 匿名對象) //由于函數(shù)的作用域因此這樣能夠?qū)崿F(xiàn),匿名函數(shù) //g函數(shù) 返回一個元素 //結(jié)論1 : 函數(shù)的返回值是一個元素 (復雜類型的), 返回的是一個新的匿名對象(所以會調(diào)用匿名對象類的copy構(gòu)造函數(shù))Location g() {Location A(1,2);return A; //因為A是一個局部變量,因此C++編譯器是調(diào)用copy構(gòu)造函數(shù)//返回的是一個匿名構(gòu)造函數(shù) }//為了完整的展現(xiàn)對象的調(diào)用聲明周期 void objplay2() {g(); }// void objplay3() {//用匿名對象初始化m 此時c++編譯器 直接把匿名對轉(zhuǎn)成m;(扶正) 從匿名轉(zhuǎn)成有名字了mLocation m = g(); printf("匿名對象,被扶正,不會析構(gòu)掉\n");cout<<m.GetX()<<endl;; }void objplay4() {//用匿名對象 賦值給 m2后, 匿名對象被析構(gòu)Location m2(1, 2);m2 = g();printf("因為用匿名對象=給m2, 匿名對象,被析構(gòu)\n");cout<<m2.GetX()<<endl;; } int main() {objplay2();//objplay3(); // objplay4();cout<<"hello..."<<endl;system("pause");return 0; }匿名對象的去或留
#include <iostream> using namespace std;class Location { public:Location( int xx = 0 , int yy = 0 ) { X = xx ; Y = yy ; cout << "Constructor Object.\n" ; }//copy構(gòu)造函數(shù) 完成對象的初始化Location(const Location & obj) //copy構(gòu)造函數(shù) {X = obj.X; Y = obj.Y;}~Location() { cout << X << "," << Y << " Object destroyed." << endl ; }int GetX () { return X ; } int GetY () { return Y ; } private : int X , Y ; } ;// //結(jié)論2: 有關(guān) 匿名對象的去和留 //如果用匿名對象 初始化 另外一個同類型的對象, 匿名對象 轉(zhuǎn)成有名對象 //如果用匿名對象 賦值給 另外一個同類型的對象, 匿名對象 被析構(gòu)//這樣寫代碼 C++編譯器會認為你就是想返回一個新的對象的 沒有名字所以是匿名對象 Location g() {Location A(1,2);return A; }void objplay3() {//用匿名對象初始化m 此時C++編譯器 直接把匿名對象轉(zhuǎn)成m;(扶正)從匿名對象直接轉(zhuǎn)換為有名字的mLocation m = g(); //A被析構(gòu)但是 m沒有重建,因為采用的是將匿名對象轉(zhuǎn)正為m,而不是從新生成一個mprintf("匿名對象轉(zhuǎn)正,不會被析構(gòu)掉\n");cout << m.GetX() << endl; }void objplay4() {Location m2(1,2);m2 = g();cout << "因為沒有使用匿名對象 = 給m2,匿名對象,被析構(gòu)" << endl;cout << m2.GetX() << endl; } int main() {//objplay3();cout <<endl <<endl << endl << endl << endl <<endl << endl;objplay4();cout<<"hello..."<<endl;system("pause");return 0; }構(gòu)造函數(shù)的的調(diào)用規(guī)則
- 當類中沒有定義任意一個構(gòu)造函數(shù)的時候C++編譯器會提供一個默認的拷貝構(gòu)造函數(shù)和無參數(shù)構(gòu)造函數(shù)
- 當類中定義了一個拷貝構(gòu)造函數(shù)的時候,C++編譯器不會提供無參數(shù)構(gòu)造函數(shù)
- 當類中定義了任意的非拷貝構(gòu)造函數(shù)(即無參數(shù)構(gòu)造函數(shù)或有參數(shù)構(gòu)造函數(shù)),C++編譯器不會提供無參數(shù)構(gòu)造函數(shù)
- 默認拷貝構(gòu)造函數(shù)只對成員進行簡單的賦值
- 總結(jié):在定義類時 只要你寫了構(gòu)造函數(shù),你就得使用
使用C++默認的拷貝構(gòu)造函數(shù)只是使用的是淺拷貝構(gòu)造函數(shù),當有指針變量的時候只會拷貝指針變量但是不會拷貝指針指向的數(shù)據(jù)
#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std;class Name { public:Name(const char *myp){int len = strlen(myp);p = (char *)malloc(len + 1);strcpy(p,myp); }~Name(){if(p != NULL){free(p); //屏蔽改行程序能夠運行}} protected: private:char *p;int len; };void objplaymain() {Name obj1("agsuafujfa");Name obj2 = obj1; //執(zhí)行C++默認得到拷貝構(gòu)造函數(shù),但是C++編譯器只是一個淺拷貝,只是把指針變量的值拷貝過來沒有把指針變量指向的數(shù)據(jù)拷貝過來//釋放 obj2 的時候程序出現(xiàn)問題,說明**obj2**淺拷貝函數(shù),直接使用的是obj1的指針變量而不是拷貝 obj1指針變量所指向的數(shù)值 //這時再次調(diào)用obj1析構(gòu)函數(shù)的時候就會出現(xiàn)問題} int main() {objplaymain();cout << "hello world!" << endl;system("pause");return 0; }例如如圖:
在必要的時候需要程序員自己寫拷貝函數(shù)
使用深拷貝實現(xiàn)對象的賦值
解決辦法就是自己編寫拷貝函數(shù)
//等號操作符,也是默認使用的是淺拷貝,因此要是使用”= “操作符對對象進行賦值的時候需要使用操作符重載
#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std;class Name { public:Name(const char *myp){m_len = strlen(myp);p = (char *)malloc(m_len + 1);strcpy(p,myp); }//Name obj2 = obj1Name(const Name& obj){m_len = obj.m_len;p = (char *)malloc(m_len + 1);strcpy(p,obj.p);}~Name(){if(p != NULL){free(p);}} protected: private:char *p;int m_len; };void objplaymain() {Name obj1("agsuafujfa");//Name obj2= obj1; <==> obj2(obj1); //執(zhí)行C++默認得到拷貝構(gòu)造函數(shù),但是C++編譯器只是一個淺拷貝,只是把指針變量的值拷貝過來沒有把指針變量指向的數(shù)據(jù)拷貝過來Name obj3("obj3");obj1 = obj3; //等號操作 C++提供的等號操作也是一個淺拷貝 解決辦法是顯式的從在"=" 操作符 } int main() {objplaymain();cout << "hello world!" << endl;system("pause");return 0; }總結(jié)
以上是生活随笔為你收集整理的构造函数和析构函数深拷贝和浅拷贝的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 作者:邵蓥侠(1988-),男,博士,
- 下一篇: 互联网环境下分布式事务处理系统现状与趋势