04.03 【C++基礎】C++類的六個默認成員函數

C++中,類有六個默認的成員函數,如圖:

【C++基礎】C++類的六個默認成員函數

接下來就分別介紹一下這六個成員函數

1.構造函數

在C++中,許多類的成員變量都是私有的,在類外部想要對變量初始化是辦不到的,所有以必須有一個公有的函數進行初始化,而這個函數當且僅當在定義對象的時候自動執行一次,這時調用的函數叫做構造函數

構造函數是個比較特殊的成員函數,有以下幾種特點:

1.函數名與類名相同

2.沒有返回值

3.對象構造時系統自動調用對應的構造函數

4.構造函數可以重載

5.構造函數可以在類中定義,也可以在類外定義

6.如果類定義中沒有給出構造函數,則C++的編譯器會自動產生一個缺省的構造函數,但如果已定義則不會產生

7.無參的構造函數和全缺省的構造函數都是缺省的構造函數,缺省的構造函數只能有一個

無參的構造函數:

class Person{//假設名字是一個字符好了public: Person() {
_name = 'x';
_height = 188;
_weight = 150;
}private: char _name; int _height; int _weight;
};int main() {
Person p1;
Person p2();
}123456789101112131415161718

在類Person中有一個公有函數叫Person,沒有參數,這就是無參的構造函數,注意,main函數中,第一個p1是調用了無參的構造函數,而第二個p2,編譯器給出了一個警告:“Person p2(void)”: 未調用原型函數(是否是有意用變量定義的?)

所以這裡沒有調用構造函數定義出p2,注意這個錯誤

有參的構造函數:

class Person{ //假設名字是一個字符好了public: Person(char name, int high, int weight) {
_name = name;
_height = _height;
_weight = _weight;
}private: char _name; int _height; int _weight;
};int main() {
Persomn p3('q', 188, 150);//當然我肯定沒這麼高,也沒有這麼輕}1234567891011121314151617

上面的構造函數是有參數的,在初始化的時候傳入參數,就調用成功了

再看一下缺省的構造函數,根據缺省程度可以分為全缺省和半缺省:

class Person{public:
//全缺省的構造函數 Person(char name = 'q', int height = 188, int weight = 150) {
_name = name;
_height = _height;
_weight = weight;
} //半缺省的構造函數
Person(char name, int height = 188, int weight = 150) {
_name = name;
_height = _height;
_weight = weight;
}private: char _name; int _height; int _weight;
};int main() {
Person p1;//調用缺省的構造函數
Person p2('q');//調用缺省的構造函數
system("pause"); return 0;
}1234567891011121314151617181920212223242526

【默認構造函數】

類如果沒有顯式定義構造函數時,編譯器會合成一個默認的構造函數,該構造函數中什麼工作都不做。只要顯式定義了,即使該構造函數什麼也不做,編譯器也不會為該類合成默認的構造函數。編譯器生成的默認構造函數使用與變量初始化相同的規則來初始化成員,具有類類型的成員通過運行各自的默認構造函數來進行初始化。

構造函數的作用主要是:

1、構建對象

2、初始化對象

3、類型轉換

2.拷貝構造函數

在創建對象的時候用同類對象來進行初始化,這時候用的構造函數稱為拷貝構造函數,拷貝構造函數是一種特殊的構造函數

有以下幾點特徵:

1.拷貝構造函數其實是一個構造函數的重載

2.拷貝構造函數的參數必須使用引用傳參,不能使用傳值傳參

3.如果沒有定義拷貝構造函數,系統會默認缺省的拷貝構造函數,缺省的拷貝構造函數會依次拷貝類成員進行初始化

代碼如下:

class Person{public:
//全缺省的構造函數 Person(char name = 'q', int height = 188, int weight = 150) {
_name = name;
_height = _height;
_weight = weight;
}
Person(const Person& p) {
_name = p._name;
_height = p._height;
_weight = p._weight;
}private: char _name; int _height; int _weight;
};int main() {
Person p1;
Person p2(p1);
system("pause"); return 0;
}12345678910111213141516171819202122232425

這裡用const是為了避免p1的值被修改,那麼,為什麼要用引用呢?

看引用之前,我們再看一種調用拷貝函數的方式,代碼如下:

Person p3 = p1;1

上面這句也是一種使用拷貝函數的方式,那麼如果使用值傳遞,C中,函數傳遞參數的時候有兩種方式,一種是傳值方式,一種是傳址,但是這兩種其實都是傳值,在調用函數的時候對傳入的參數進行拷貝然後壓入函數的調用棧中,所以,如果是傳值調用,就會出現這種情況:

p = p1;//注意這種情況,p為形參,p1為原值1

這種情況是不是跟上面調用拷貝函數的方式一樣,那麼接下來它就會繼續調用拷貝構造函數,這樣就會無限遞歸下去

注意,在大多數情況下,我們應該自己寫出拷貝構造函數,即使系統會給我們合成它,因為系統生成的只是一種淺拷貝,比如:

char* str1 = "abcdef";char str2[7];12

上面的這樣兩個字符串數組,如果是我們自己拷貝,應該是一個一個對字符進行拷貝,如果是系統自動生成的默認拷貝函數,它就會直接複製,結果是str2也指向了str1的那串字符串,而不是去進行拷貝,這樣就很可能出錯

3.析構函數

在一個對象的聲明週期結束時,編譯器會自動調用一個成員函數,這個特殊的函數叫做析構函數,析構函數的特徵如下:

1.析構函數名是在類名前加上字符~

2.析構函數無參數無返回值

3.一個類只有一個析構函數,若未定義則自動生成缺省的析構函數

4.對象的生命週期結束時,編譯器自動調用析構函數

5.析構函數內部並不是刪除對象而是在做一些清理工作

4.賦值操作符重載

研究賦值操作符重載之前,先搞清楚運算符重載是什麼?

運算符重載的實質就是函數重載或函數多態。

運算符重載是一種形式的C++多態。目的在於讓人能夠用同名的函數來完成不同的基本操作。要重載運算符,需要使用被稱為運算符函數的特殊函數形式

運算符函數形式:operator p(argument-list)//p為運算符

運算符函數的參數至少有一個必須是類的對象或者類的對象的引用。這種規定可以防止改變內置類型的函義。

以下5個不能重載的運算符:

. (成員訪問運算符) .*(指針訪問運算符) :: (與運算符) sizeof (大小運算符) ?: (條件運算符)

所以,賦值操作符重載的代碼如下:

Person& operator=(Person& p) { /*
**這裡面應該是具體的賦值
*/
return *this;
}123456

5.取地址操作符重載

Person& operator&() { return *this;
}1234

6.const修飾的取地址符重載

const Person& Person&() { return *this;
}123


分享到:


相關文章: