<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] # 簡介 當我們創建對象的時候,這個對象應該有一個初始狀態,當對象銷毀之前應該銷毀自己創建的一些數據。 對象的初始化和清理也是兩個非常重要的安全問題,一個對象或者變量沒有初始時,對其使用后果是未知,同樣的使用完一個變量,沒有及時清理,也會造成一定的安全問題。c++為了給我們提供這種問題的解決方案,構造函數和析構函數,這兩個函數將會被編譯器自動調用,完成對象初始化和對象清理工作。 無論你是否喜歡,對象的初始化和清理工作是編譯器強制我們要做的事情,即使你不提供初始化操作和清理操作,編譯器也會給你增加默認的操作,只是這個默認初始化操作不會做任何事,所以編寫類就應該順便提供初始化函數。 為什么初始化操作是自動調用而不是手動調用?既然是必須操作,那么自動調用會更好,如果靠程序員自覺,那么就會存在遺漏初始化的情況出現 # 構造函數和析構函數 構造函數主要作用在于創建對象時為對象的成員屬性賦值,構造函數由編譯器自動調用,無須手動調用。 析構函數主要用于對象銷毀前系統自動調用,執行一些清理工作。 構造函數語法: * 構造函數函數名和類名相同,沒有返回值,不能有void,但可以有參數。 ~~~ ClassName(){} ~~~ 析構函數語法: * 析構函數函數名是在類名前面加”~”組成,沒有返回值,不能有void,不能有參數,不能重載。 ~~~ ~ClassName(){} ~~~ ~~~ class Person{ public: Person(){ cout << "構造函數調用!" << endl; pName = (char*)malloc(sizeof("John")); strcpy(pName, "John"); mTall = 150; mMoney = 100; } ~Person(){ cout << "析構函數調用!" << endl; if (pName != NULL){ free(pName); pName = NULL; } } public: char* pName; int mTall; int mMoney; }; void test(){ Person person; cout << person.pName << person.mTall << person.mMoney << endl; } ~~~ # 注意點 1. 構造函數和析構函數權限必須是公有的 2. 構造函數可以重載 3. 構造函數沒有返回值,不能用void,構造函數可以有參數,析構函數沒有返回值,不能用void,沒有參數 4. 如果類有成員對象,先調用成員對象的構造函數,再調用自己的,析構順序反之 5. 成員對象的構造函數調用和定義順序一樣 # 構造函數的分類 * 按參數類型:分為無參構造函數和有參構造函數 * 按類型分類:普通構造函數和拷貝構造函數(復制構造函數) 拷貝構造是沒有對象的時候調用的 ~~~ class Person{ public: Person(){ cout << "no param constructor!" << endl; mAge = 0; } //有參構造函數 Person(int age){ cout << "1 param constructor!" << endl; mAge = age; } //拷貝構造函數(復制構造函數) 使用另一個對象初始化本對象 Person(const Person& person){ cout << "copy constructor!" << endl; mAge = person.mAge; } //打印年齡 void PrintPerson(){ cout << "Age:" << mAge << endl; } private: int mAge; }; //1. 無參構造調用方式 void test01(){ //調用無參構造函數 Person person1; person1.PrintPerson(); //無參構造函數錯誤調用方式 //Person person2(); //person2.PrintPerson(); } //2. 調用有參構造函數 void test02(){ //第一種 括號法,最常用 Person person01(100); person01.PrintPerson(); //調用拷貝構造函數 Person person02(person01); person02.PrintPerson(); //第二種 匿名對象(顯示調用構造函數) Person(200); //匿名對象,沒有名字的對象 Person person03 = Person(300); person03.PrintPerson(); //注意: 使用匿名對象初始化判斷調用哪一個構造函數,要看匿名對象的參數類型 Person person06(Person(400)); //等價于 Person person06 = Person(400); person06.PrintPerson(); //第三種 =號法 隱式轉換 Person person04 = 100; //Person person04 = Person(100) person04.PrintPerson(); //調用拷貝構造 Person person05 = person04; //Person person05 = Person(person04) person05.PrintPerson(); } ~~~ b為A的實例化對象,`A a = A(b)` 和 A(b)的區別? 當A(b) 有變量來接的時候,那么編譯器認為他是一個匿名對象,當沒有變量來接的時候,編譯器認為你A(b) 等價于 `A b.` 注意:不能調用拷貝構造函數去初始化匿名對象,也就是說以下代碼不正確: ~~~ class Teacher{ public: Teacher(){ cout << "默認構造函數!" << endl; } Teacher(const Teacher& teacher){ cout << "拷貝構造函數!" << endl; } public: int mAge; }; void test(){ Teacher t1; //error C2086:“Teacher t1”: 重定義 Teacher(t1); //此時等價于 Teacher t1; } ~~~ # 構造函數調用規則 默認情況下,c++編譯器至少為我們寫的類增加3個函數 1. 默認構造函數(無參,函數體為空) 2. 默認析構函數(無參,函數體為空) 3. 默認拷貝構造函數,對類中非靜態成員屬性簡單值拷貝 * 如果用戶定義拷貝構造函數,c++不會再提供任何默認構造函數 * 如果用戶定義了普通構造(非拷貝),c++不在提供默認無參構造,但是會提供默認拷貝構造 # 拷貝構造為什么是const引用 ~~~ CBox(CBox initB);//復制構造函數一開始想到的原型 CBox cigar; CBox myBox(cigar); //如果編寫這樣一條語句 //那么將生成這樣一條對復制構造函數的調用CBox::CBox(cigar); ~~~ 因為實參是通過按值傳遞機制傳遞的。在可以傳遞對象cigar之前,編譯器需要安排創建該對象的副本。因此,編譯器為了處理復制構造函數的這條調用語句,需要調用復制構造函數來創建實參的副本。但是,由于是按值傳遞,第二次調用同樣需要創建實參的副本,因此還得調用復制構造函數,就這樣持續不休。最終得到的是對復制構造函數的無窮調用。(其實就是創建副本也是需要調用復制構造函數的) 所以解決辦法先是要將形參改為引用形參: ~~~ CBox (CBox &initB); ~~~ 其實,這里,如果不去改變實參的值的話,不加const的效果和加const的效果是一樣的,而且不加const編譯器也不會報錯,因為函數的形參是引用,則調用函數時不需要復制實參,函數是直接訪問調用函數中的實參變量的。但是為了整個程序的安全,還是加上const,防止對實參的意外修改 # 返回值優化 局部變量,內存不釋放 relase地址一樣,debug不一樣 ~~~ //局部對象以值的方式從函數返回 //vs Debug模式下會調用拷貝構造,relase模式下 Person show() { //局部對象 Person p; cout << "局部對象的地址: " << &p << endl; return p; } int main() { Person p1 = show(); cout << "m1對象的地址: " << &p1 << endl; system("pause"); return EXIT_SUCCESS; } ~~~ # 多個對象 構造函數和其他函數不同,除了有名字,參數列表,函數體之外還有初始化列表。 在類中定義的數據成員一般都是基本的數據類型。但是類中的成員也可以是對象,叫做對象成員。 C++中對對象的初始化是非常重要的操作,當創建一個對象的時候,c++編譯器必須確保調用了所有子對象的構造函數。如果所有的子對象有默認構造函數,編譯器可以自動調用他們。但是如果子對象沒有默認的構造函數,或者想指定調用某個構造函數怎么辦? 那么是否可以在類的構造函數直接調用子類的屬性完成初始化呢?但是如果子類的成員屬性是私有的,我們是沒有辦法訪問并完成初始化的。 解決辦法非常簡單:對于子類調用構造函數,c++為此提供了專門的語法,即構造函數初始化列表。 當調用構造函數時,首先按各對象成員在類定義中的順序(和參數列表的順序無關)依次調用它們的構造函數,對這些對象初始化,最后再調用本身的函數體。也就是說,先調用對象成員的構造函數,再調用本身的構造函數。 析構函數和構造函數調用順序相反,先構造,后析構。 ~~~ //初始化列表可以指定調用構造函數 Person(string carName, string tracName, string name) : mTractor(tracName), mCar(carName), mName(name){ cout << "Person 構造函數!" << endl; } ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看