https://www.toutiao.com/article/7221780830300160527/?log_from=e246e008cd46d_1681705879867 (構(gòu)造函數(shù)是用來初始化對象的特殊成員函數(shù)它們的名稱與類的名稱相同一個(gè)類可以有多個(gè)構(gòu)造函數(shù)以便在創(chuàng)建對象時(shí)使用不同的參數(shù)列表) C++構(gòu)造函數(shù) C++構(gòu)造函數(shù)| 構(gòu)造函數(shù)基礎(chǔ) https://www.toutiao.com/article/7221780830300160527/?log_from=e246e008cd46d_1681705879867C++中的構(gòu)造函數(shù)是用來初始化對象的特殊成員函數(shù),它們的名稱與類的名稱相同。構(gòu)造函數(shù)在創(chuàng)建類的新對象時(shí)自動(dòng)調(diào)用,用于對對象進(jìn)行初始化工作,比如給屬性賦初值。一個(gè)類可以有多個(gè)構(gòu)造函數(shù),以便在創(chuàng)建對象時(shí)使用不同的參數(shù)列表。所以構(gòu)造函數(shù)的長相決定了對象的長相,無參構(gòu)造函數(shù),對象無參,一個(gè)參數(shù)構(gòu)造函數(shù),對象一個(gè)參數(shù),以此類推。 構(gòu)造函數(shù)的特點(diǎn):
如下測試代碼: #include <iostream> #include <string> class GirlFriend { public: GirlFriend(std::string name, int age) { m_name = name; m_age = age; std::cout << "兩個(gè)參數(shù):構(gòu)造函數(shù)" << std::endl; } void print() { std::cout << m_name<<"\t"<< m_age << std::endl; } protected: std::string m_name; private: int m_age; }; int main() { //錯(cuò)誤沒有一個(gè)參數(shù)的構(gòu)造函數(shù) //GirlFriend object; //1.構(gòu)造對象 GirlFriend object("baby", 18); object.print(); //2.new一個(gè)對象 GirlFriend* p = new GirlFriend("小芳", 29); p->print(); //3.隱式轉(zhuǎn)換創(chuàng)建,必須具備兩個(gè)參數(shù)構(gòu)造函數(shù) GirlFriend girl = { "小美",28 }; girl.print(); return 0; } 結(jié)構(gòu)體中包含構(gòu)造函數(shù),也是一樣的規(guī)則,不能再使用C語言的方式去創(chuàng)建結(jié)構(gòu)體變量。 C++構(gòu)造函數(shù)| explicit 禁止隱式轉(zhuǎn)換 在C++中,關(guān)鍵字explicit通常用于構(gòu)造函數(shù)聲明。使用explicit關(guān)鍵字可以防止隱式轉(zhuǎn)換,以便只有顯式調(diào)用才能將單個(gè)參數(shù)構(gòu)造函數(shù)作為隱式轉(zhuǎn)換執(zhí)行。如下測試代碼: #include <iostream> #include <string> class GirlFriend { public: explicit GirlFriend(std::string name, int age) { m_name = name; m_age = age; } void print() { std::cout << m_name<<"\t"<< m_age << std::endl; } protected: std::string m_name; private: int m_age; }; int main() { //錯(cuò)誤:禁止隱式轉(zhuǎn)換 //GirlFriend girl = { "小美",28 }; GirlFriend girl("小美", 28); girl.print(); return 0; } C++構(gòu)造函數(shù)| delete與default 在C++類中, delete與default都是關(guān)鍵字。
如下測試代碼: #include <iostream> #include <string> class GirlFriend { public: //刪掉默認(rèn)構(gòu)造函數(shù) GirlFriend() = delete; protected: }; class BoyFriend { public: //使用默認(rèn)的構(gòu)造函數(shù),故可以創(chuàng)建無參對象 BoyFriend() = default; BoyFriend(int age) {} protected: }; int main() { //錯(cuò)誤,默認(rèn)構(gòu)造函數(shù)被刪除,不存在構(gòu)造函數(shù),無法創(chuàng)建對象 //GirlFriend girl; //調(diào)用默認(rèn)函數(shù)構(gòu)造無參對象 BoyFriend boy; BoyFriend moying(18); return 0; } C++構(gòu)造函數(shù)| 構(gòu)造函數(shù)委托 在C++11中,我們可以使用構(gòu)造函數(shù)委托來簡化類的構(gòu)造函數(shù)。構(gòu)造函數(shù)委托可以讓一個(gè)構(gòu)造函數(shù)調(diào)用另一個(gè)構(gòu)造函數(shù)來完成部分或全部的初始化工作。調(diào)用方式必須用初始化參數(shù)列表方式。 #include <iostream> #include <string> class GirlFriend { public: GirlFriend(std::string name,int age) { m_name = name; m_age = age; } //構(gòu)造函數(shù)委托,初始化參數(shù)列表 GirlFriend() :GirlFriend("默認(rèn)", 0) { } void print() { std::cout << m_name << "\t" << m_age << std::endl; } protected: std::string m_name; int m_age; }; int main() { GirlFriend object; object.print(); return 0; } C++構(gòu)造函數(shù)| 匿名對象 C++中的匿名對象是指沒有被命名的臨時(shí)對象。匿名對象是一個(gè)右值,引用傳參需要用常引用或者右值引用,它們通常在函數(shù)調(diào)用的時(shí)候被創(chuàng)建,用于傳遞參數(shù)或作為函數(shù)返回值。 匿名對象的生命周期僅限于當(dāng)前表達(dá)式或語句結(jié)束之前,在此之后便會(huì)被銷毀。 以下是一些產(chǎn)生匿名對象的常見方式:
如下測試代碼: #include <iostream> #include <string> class GirlFriend { public: GirlFriend(std::string name,int age) { m_name = name; m_age = age; } void print() { std::cout << m_name << "\t" << m_age << std::endl; } protected: std::string m_name; int m_age; }; //用常引用需要調(diào)用常成員函數(shù) void printObject(GirlFriend&& object) { object.print(); } GirlFriend returnObject() { return GirlFriend("匿名對象", 18); } int main() { GirlFriend object=GirlFriend("匿名對象",18); object.print(); printObject(GirlFriend("匿名對象", 18)); returnObject().print(); return 0; } C++析構(gòu)函數(shù)C++中析構(gòu)函數(shù)是一種特殊的成員函數(shù),用于在對象銷毀時(shí)清理對象所占用的資源。析構(gòu)函數(shù)的名稱與類名相同,前面加上一個(gè)波浪號(~),沒有參數(shù)。 析構(gòu)函數(shù)在以下情況下會(huì)被自動(dòng)調(diào)用:
析構(gòu)函數(shù)可以在銷毀對象時(shí)執(zhí)行必要的內(nèi)存清理操作,如釋放動(dòng)態(tài)分配的內(nèi)存、關(guān)閉文件等資源。如果一個(gè)類擁有指向其他對象的指針、動(dòng)態(tài)分配了內(nèi)存或打開了文件,那么這個(gè)類應(yīng)該定義一個(gè)析構(gòu)函數(shù)來處理這些操作,以避免內(nèi)存泄漏和資源浪費(fèi)的問題。 如下測試代碼: #include <iostream> #include <string> class GirlFriend { public: ~GirlFriend() { std::cout << "析構(gòu)函數(shù)" << std::endl; } protected: }; int main() { { //普通對象代碼塊結(jié)束調(diào)用析構(gòu) GirlFriend girl; //new出來的對象需要delete才會(huì)調(diào)用析構(gòu) GirlFriend* p = new GirlFriend; } std::cout << "--------------" << std::endl; { //普通對象代碼塊結(jié)束調(diào)用析構(gòu) GirlFriend girl; //new出來的對象需要delete才會(huì)調(diào)用析構(gòu) GirlFriend* p = new GirlFriend; delete p; } return 0; } 運(yùn)行結(jié)果如下: C++拷貝構(gòu)造函數(shù)C++的拷貝構(gòu)造函數(shù)(Copy Constructor)是一種特殊的構(gòu)造函數(shù),用于創(chuàng)建一個(gè)新對象并且以傳入的同類對象為初始值。拷貝構(gòu)造函數(shù)在許多場合下自動(dòng)被調(diào)用,例如當(dāng)函數(shù)參數(shù)是一個(gè)對象時(shí)、當(dāng)函數(shù)返回值是一個(gè)對象時(shí)、當(dāng)一個(gè)對象被另一個(gè)對象賦值時(shí),等等。拷貝構(gòu)造函數(shù)唯一的參數(shù)就是對對象的引用,作用就是通過一個(gè)對象產(chǎn)生另一個(gè)對象。 C++拷貝構(gòu)造函數(shù)| 左值引用 左值引用的拷貝構(gòu)造函數(shù),只能實(shí)現(xiàn)左值對象的拷貝,不能傳入常對象,或者右值對象。如下測試代碼: #include<iostream> #include<string> class MM { public: MM() {} MM(std::string name, int age) { m_name = name; m_age = age; } //拷貝構(gòu)造函數(shù)+構(gòu)造函數(shù)委托 MM(MM& object):MM(object.m_name,object.m_age) { } void print() { std::cout << m_name << "\t" << m_age << std::endl; } protected: std::string m_name; int m_age; }; //不調(diào)用 void printInfo(MM& object) { object.print(); } //調(diào)用拷貝構(gòu)造函數(shù) void printData(MM object) { object.print(); } int main() { MM girl("girl", 19); //調(diào)用拷貝構(gòu)造函數(shù) MM mm = girl; mm.print(); //調(diào)用拷貝構(gòu)造函數(shù) MM baby(mm); baby.print(); //錯(cuò)誤 //MM error1 = std::move(baby); //錯(cuò)誤 //MM error2(MM("error", 18)) ; MM test; //不調(diào)用拷貝構(gòu)造函數(shù) test = mm; printInfo(test); printData(test); return 0; } C++拷貝構(gòu)造函數(shù)| 常引用 常引用的拷貝構(gòu)造函數(shù)要注意的是在拷貝構(gòu)造函數(shù)中不能修改數(shù)據(jù)成員?;旧蠞M足大部分的需求。如下測試代碼: #include<iostream> #include<string> class MM { public: MM() {} MM(std::string name, int age) { m_name = name; m_age = age; } //拷貝構(gòu)造函數(shù)+構(gòu)造函數(shù)委托 MM( const MM& object):MM(object.m_name,object.m_age) { //這個(gè)函數(shù)中不能修改object數(shù)據(jù) } void print() { std::cout << m_name << "\t" << m_age << std::endl; } protected: std::string m_name; int m_age; }; //不調(diào)用 void printInfo(MM& object) { object.print(); } //調(diào)用拷貝構(gòu)造函數(shù) void printData(MM object) { object.print(); } int main() { MM girl("girl", 19); //調(diào)用拷貝構(gòu)造函數(shù) MM mm = girl; mm.print(); //調(diào)用拷貝構(gòu)造函數(shù) MM baby(mm); baby.print(); //正確 MM ok1 = std::move(baby); MM ok2(MM("error", 18)); MM test; //不調(diào)用拷貝構(gòu)造函數(shù) test = mm; printInfo(test); printData(test); return 0; } C++拷貝構(gòu)造函數(shù)| 右值引用 C++11引入了移動(dòng)語義(Move Semantics)的概念,這種語義的目的是在對象拷貝的過程中避免不必要的復(fù)制操作,從而提高程序的性能。移動(dòng)拷貝(Move Constructor)是一種特殊的構(gòu)造函數(shù),用于將另一個(gè)同類對象的資源所有權(quán)移動(dòng)到一個(gè)新對象中,即移動(dòng)拷貝不是復(fù)制原有對象的數(shù)據(jù),而是基于原對象構(gòu)造一個(gè)新對象,并將原對象的資源指針移到新對象,使新對象掌握該資源的控制權(quán)。相比于常引用來說,在拷貝構(gòu)造函數(shù)中可以修改數(shù)據(jù)。如下測試代碼: #include<iostream> #include<string> class MM { public: MM() {} MM(std::string name, int age) { m_name = name; m_age = age; } //拷貝構(gòu)造函數(shù)+構(gòu)造函數(shù)委托 MM(MM& object):MM(object.m_name,object.m_age) { } MM(MM&& object) :MM(object.m_name, object.m_age) { object.m_name = "name"; } void print() { std::cout << m_name << "\t" << m_age << std::endl; } protected: std::string m_name; int m_age; }; //不調(diào)用 void printInfo(MM& object) { object.print(); } //調(diào)用拷貝構(gòu)造函數(shù) void printData(MM object) { object.print(); } int main() { MM girl("girl", 19); //調(diào)用拷貝構(gòu)造函數(shù) MM mm = girl; mm.print(); //調(diào)用拷貝構(gòu)造函數(shù) MM baby(mm); baby.print(); //正確 MM ok1 = std::move(baby); MM ok2(MM("error", 18)); printInfo(baby); printData(baby); return 0; } C++拷貝構(gòu)造函數(shù)| 深淺拷貝問題C++類中包含指針的時(shí)候并且做內(nèi)存申請,才會(huì)存在深淺拷貝問題。
通常不寫拷貝構(gòu)造函數(shù),會(huì)存在一個(gè)默認(rèn)的拷貝構(gòu)造函數(shù),默認(rèn)拷貝構(gòu)造和直接賦值的拷貝構(gòu)造都是淺拷貝,淺拷貝會(huì)引發(fā)內(nèi)存重復(fù)被釋放問題。如下測試代碼: #include <iostream> #include <cstring> using namespace std; class MM { public: MM(const char* str) { int length = strlen(str) + 1; pname = new char[length]; strcpy_s(pname, length, str); } MM(MM& object) { //默認(rèn)拷貝構(gòu)造和直接賦值都是淺拷貝 pname = object.pname; } void print() { cout << pname << endl; } ~MM() { delete[] pname; } protected: char* pname; }; int main() { { MM mm("淺拷貝"); MM girl(mm); girl.print(); mm.print(); } return 0; } 運(yùn)行結(jié)果如下: 深拷貝實(shí)現(xiàn)代碼: #include <iostream> #include <cstring> using namespace std; class MM { public: MM(const char* str) { int length = strlen(str) + 1; pname = new char[length]; strcpy_s(pname, length, str); } //委托構(gòu)造 MM(MM& object):MM(object.pname) { //或者自己實(shí)現(xiàn)代碼 //int length = strlen(object.pname) + 1; //pname = new char[length]; //strcpy_s(pname, length, object.pname); } void print() { cout << pname << endl; } ~MM() { delete[] pname; } protected: char* pname; }; int main() { { MM mm("深拷貝"); MM girl(mm); girl.print(); mm.print(); } return 0; } 做了內(nèi)存的在申請,這樣就不會(huì)有問題。 C++構(gòu)造和析構(gòu)順序C++構(gòu)造和析構(gòu)順序主要有以下三點(diǎn):
如下測試代碼: #include <iostream> #include <string> using namespace std; class MM { public: MM(string _name="默認(rèn)") { name = _name; cout << name; } ~MM() { cout << name; } protected: string name; }; int main() { //普通對象,構(gòu)造順序和析構(gòu)順序相反 cout << "普通對象,構(gòu)造順序和析構(gòu)順序相反" << endl; { MM a("a"); MM b("b"); MM c("c"); } cout <<endl <<"new出來的對象,立刻馬上調(diào)用析構(gòu)" << endl; { MM a("a"); MM b("b"); auto c = new MM("c"); delete c; MM d("d"); //abccddba } cout <<endl << "static對象最后被釋放" << endl; { MM a("a"); MM b("b"); static MM s(" static "); MM c("c"); } cout << endl << "C++構(gòu)造數(shù)組對象,一般會(huì)準(zhǔn)備無參構(gòu)造函數(shù)" << endl; { //MM array[3]{ {"a"},{"b"},{"c"}}; //帶參的方式構(gòu)造,比較不推薦 //構(gòu)造數(shù)組其實(shí)是三個(gè)無參對象 MM a("a"); MM arr[3]; MM b("b"); } return 0; } 如果能成功分析程序運(yùn)行結(jié)果,基本就沒什么問題。程序運(yùn)行結(jié)果如下: 相關(guān)如果閣下正好在學(xué)習(xí)C/C++,看文章比較無聊,不妨關(guān)注下關(guān)注下小編的視頻教程,通俗易懂,深入淺出,一個(gè)視頻只講一個(gè)知識點(diǎn)。視頻不深?yuàn)W,不需要鉆研,在公交、在地鐵、在廁所都可以觀看,隨時(shí)隨地漲姿勢。 |
|