目錄
1.引言
2.構造函數
1.概念
2.特性
3.析構函數
1.概念
2.特性
1.引言
? ? ? ?? ? 如果一個類中什么都沒有,叫作空類.
class A {};
????????那么我們這個類中真的是什么都沒有嗎?其實不是,如果我們類當中上面都不寫.編譯器會生成6個默認的成員函數。
????????默認成員函數:用戶沒有顯示寫 , 編譯器自動生成的函數。
????????這里我們只介紹兩個構造函數,析構函數
2.構造函數
class Stack {
public:void init(int defaultCapacity) {_a = new int[defaultCapacity];_top = 0;}void destory() {delete[] _a;_top = 0;}
private:int* _a;int _top;
};
int main() {Stack s;s.init();return 0;
}
? ? ? ? 我們想要去寫一個棧,但是我們每次都要調用init去初始化非常麻煩,那么我們有沒有上面方法不用寫init()呢?有的,所以我們就引出了構造函數.
1.概念
? ? ? ? 構造函數是一個默認的成員函數,名字與類名相同,每次創建對象的時候自動調用,完成對象的初始化,在生命周期內只會調用一次。
2.特性
? ? ? ? 1.名字與類名相同.
? ? ? ? 2.無返回值
? ? ? ????????? 例如:我們上面的棧
?Stack()? {_a = new int[4];_top = 0;}
? ? ? ? 3.可以進行重載
帶參數
Stack(int defaultCapacity) {_a = new int[defaultCapacity];_top = 0;
}不帶參數
Stack() {_a = new int[4];_top = 0;
}
? ? ? ? 4.自動調用
class A {
public:A() {cout << "A()" << endl;}
};
int main() {A a;return 0;
}
? ? ? ? 例如我們有一個類A,它有一個無參的構造函數,我們在創建對象的時候,沒有顯示的調用構造函數,但是是我們調用的時候會打印出A().
? ? ? ? 這是因為我們的構造函數,在創建對象的時候會自動調用,來初始化對象。
5.用戶定義的時候就不會再生成
? ? ? ? 我們把A改為不帶構造函數的類
class A {
public:
};
int main() {A a;return 0;
}
? ? ? ? 我們看到沒有報錯,因為編譯器在我們沒有寫構造函數的時候生成一個隱式不帶參數的構造函數.
? ? ? ? 還是上面的例子,我們把A的構造函數改成帶有一個參數的構造函數.
class A {
public:A(int a) {cout << "A(a)" << endl;}
};
int main() {A a;return 0;
}
????????這個時候,我們在像剛才一樣創建對象編譯器就會報錯。
? ? ? ? 這是因為我們沒有寫構造函數的時候,編譯器會默認生成一個不帶參數的構造函數.如果我們顯示寫了構造函數編譯器就不會生成。
6.生成默認構造對內置類型不進行處理
? ? ? ?還是上面的例子,我們把類A中添加結果成員變量
class A {
public:int _a;double _d;int* _ptr;
};
int main() {A a;return 0;
}
? ? ? ? 這個時候我們沒有顯示的寫構造函數,這個時候編譯器會自動生成一個不帶參數的構造函數.
這個時候我們想看到默認構造對內置類型做不做處理怎么辦?這個時候我們可以通過調式去看
????????我們看一下調式結果,_a和_d都為隨機值,這說明我們生成的默認構造對內置類型不做處理.那么我們以后是不是都要寫構造函數呢?
? ? ? ? ?其實不是,在c++在聲明的時候可以給缺省值.這個時候我們給缺省值,再調式看一下結果.
? ? ?7.? 默認構造函數:? 編譯器自動生成,無參,全缺省都可以稱為默認構造函數
class A {
public:A() {cout << "A()" << endl;}A(int a = 1, int b = 1) {cout << "A(int a = 1, int b = 1)" << endl;}int _a;int _b;
};
int main() {A a;return 0;
}
? ? ? ? 什么的代碼編譯器會報錯這是為什么?因為,無參的和全缺省的都可以不傳參數,編譯器無法辨別調用哪一個.所以就會報錯.
3.析構函數
? ? ? ? 還是上面的棧,如果我們想讓銷毀棧,每次都要調用destroy非常麻煩,而且有時候我們會忘記調用,這個就會導致內存泄漏導致程序崩潰。所以我們c++就引出一個新的默認成員函數叫作析構函數.
1.概念
? ? ? ? 與構造函數的功能相反,析構函數是用來清理對象內的資源的,不是用來銷毀對象,局部的對象銷毀,是編譯器來完成的。
2.特性
? ? ? ? 1.在類名前面加上~
? ? ? ? 2.無返回值
? ? ? ? 例如:
-Stack() {
}
3.一個類中只能有一個析構函數,和構造函數一樣如果我們不顯示定義析構函數,編譯器就會自動生成(析構函數不能重載)
?4.析構函數會自動調用
class A {
public:~A() {cout << "~A()" << endl;}
};
int main() {A a;return 0;
}
? ? ? ? 我們這個代碼沒有顯示的調用析構函數,但是最后的結果卻輸出~A().
????????這就說明了我們的析構函數和構造函數一樣是自動調用.
?5.編譯器生成的默認成員函數對自定義類型自動調用自定義類型的構造函數
class B {
public:~B() {cout << "~B()" << endl;}
};
class A {
public:B _b;
};
int main() {A a;return 0;
}
? ? ? ? 什么代碼中A類當中有一個自定義類型B,并且A當中沒用顯示的寫析構函數,是由編譯器自動生成的構造函數.我們看一下運行之后的結果是什么?
????????
? ? ? ? 我們可以看到輸出了~B(),說明編譯器默認生成的析構函數,對自定義類型會去調用的它的析構函數.
? ? ? ? 6.如果類當中沒有定義資源,那么我們的析構函數可以不寫,直接用編譯器生成的析構函數即可.