国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

?【C++要笑著學(xué)】(7) 默認(rèn)成員函數(shù):構(gòu)造函數(shù) | 析構(gòu)函數(shù) | 拷貝構(gòu)造函數(shù)

這篇具有很好參考價值的文章主要介紹了?【C++要笑著學(xué)】(7) 默認(rèn)成員函數(shù):構(gòu)造函數(shù) | 析構(gòu)函數(shù) | 拷貝構(gòu)造函數(shù)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

?? 訂閱量破千的火熱 C++ 教程
?? 火速訂閱
《C++要笑著學(xué)》?

??? CSDN 累計訂閱量破千的火爆 C/C++ 教程的 2023 重制版,C 語言入門到實(shí)踐的精品級趣味教程。
了解更多: ???"不太正經(jīng)" 的專欄介紹?試讀第一章
訂閱鏈接: ??《C語言趣味教程》?← 猛戳訂閱!

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)? 本篇博客全站綜合熱榜最高排名:7

?? 本篇博客是本專欄最受歡迎的一篇 ??

  • ?? 寫在斜面:朋友們好啊,我是亦優(yōu)葉子,今天終于更新了。本章將繼續(xù)講解C++中的面向?qū)ο蟮闹R點(diǎn),本篇主要講解默認(rèn)成員函數(shù)中的構(gòu)造函數(shù)、析構(gòu)函數(shù)和拷貝構(gòu)造函數(shù)。還是和以前一樣,我們將由淺入深地去講解,以 "初學(xué)者" 的角度去探索式地學(xué)習(xí)。會一步步地推進(jìn)講解,而不是直接把枯燥的知識點(diǎn)倒出來,應(yīng)該會有不錯的閱讀體驗。保證文章非常有意思!不信你可以讀一讀。本章內(nèi)容全是干貨,是 C++ 面向?qū)ο蟮闹匾鹿?jié)!?如果覺得不錯,可以 "一鍵三連" 支持一下博主!你們的關(guān)注就是我更新的最大動力!
  • 【2023.9.27 更新】評論區(qū)對于此問題也有不少提問,這里我再做一個補(bǔ)充說明:這兩個問題實(shí)際上都是在問析構(gòu)順序的,只要把這塊知識點(diǎn)搞明白就會很好理解(講解在本章的 Ⅲ 0x03)

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

?? 本章目錄:

目錄

Ⅰ.? 默認(rèn)成員函數(shù)(Default member function)

Ⅱ. 構(gòu)造函數(shù)(Constructor)

0x00 引入:為什么要有構(gòu)造函數(shù)?

0x01 構(gòu)造函數(shù)的概念

0x02 構(gòu)造函數(shù)的特性

0x03 默認(rèn)構(gòu)造函數(shù)

0x04 構(gòu)造函數(shù)的特性的測試

Ⅲ. 析構(gòu)函數(shù)(Destructor)

0x00 引入:專門 “擦屁股” 的析構(gòu)函數(shù)

0x01 析構(gòu)函數(shù)的概念

0x02 析構(gòu)函數(shù)的特性

0x03 析構(gòu)順序問題

0x04?析構(gòu)函數(shù)的特性的測試

Ⅳ.? 拷貝構(gòu)造函數(shù)(Copy Constructor)

0x00 引入:可以幫我拷貝嗎?可以!

0x01 拷貝構(gòu)造函數(shù)的概念

0x02 拷貝構(gòu)造函數(shù)的特性

0x03 關(guān)于默認(rèn)生成的拷貝構(gòu)造

Ⅴ.? 總結(jié)(構(gòu)造&析構(gòu)&拷貝構(gòu)造)

0x00 構(gòu)造函數(shù)?

0x01 析構(gòu)函數(shù)

0x02 拷貝構(gòu)造


Ⅰ.? 默認(rèn)成員函數(shù)(Default member function)

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

如果一個類中什么成員都沒有,我們稱之為 "空類" 。

但是空類中真的什么都沒有嗎?答案是否定的!

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?類有六個默認(rèn)成員函數(shù),特殊的點(diǎn)非常多,我們本章就來好好學(xué)學(xué)。

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?對于 默認(rèn)成員函數(shù),如果我們不主動實(shí)現(xiàn),編譯器會自己生成一份。

? 它們有什么用呢?舉個例子:比如我們在上一章里舉過的一個 Stack 的例子。

如果需要初始化和清理,"構(gòu)造函數(shù)" 和 "析構(gòu)函數(shù)" 就可以幫助我們完成。

構(gòu)造函數(shù)就類似于 Init,而析構(gòu)函數(shù)就類似于 Destroy。

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)? 沒錯,就是這么的爽!

還是和以前一樣,我們將先由淺入深地進(jìn)行學(xué)習(xí),我們先從最簡單的?"構(gòu)造函數(shù)" 開始講起。

Ⅱ. 構(gòu)造函數(shù)(Constructor)

0x00 引入:為什么要有構(gòu)造函數(shù)?

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)打開宇宙第一編輯器,一起敲一敲看看 ~

為了能夠更好地講解,我們來寫一個簡單的日期類,通過日期類來講解!

?? 代碼演示:Date.cpp

#include <iostream>

class Date {
public:
    void SetDate(int year, int month, int day) {
        _year = year;
        _month = month;
        _day = day;
    }
    void Print() {
        printf("%d-%d-%d\n", _year, _month, _day);
    }

private:
    int _year;
    int _month;
    int _day;
};

int main(void)
{
    Date d1;
    d1.SetDate(2022, 3, 8);
    d1.Print();

    Date d2;
    d2.SetDate(2022, 3, 12);
    d2.Print();

    return 0;
}

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?對于 Date 類,我們可以通過我們寫的成員函數(shù)?SetDate 給對象設(shè)置內(nèi)容。

但是每次創(chuàng)建對象都要調(diào)用這個 SetDate ,是不是太雞兒煩了?

? 那有沒有什么辦法能在創(chuàng)建對象時,自動將我們要傳遞的內(nèi)容放置進(jìn)去呢?

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?有!下面我們來隆重介紹一下 構(gòu)造函數(shù)

0x01 構(gòu)造函數(shù)的概念

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?構(gòu)造函數(shù)是一個特殊的成員函數(shù):

  • 名字與類名相同(寫起來簡單又草率)
  • 創(chuàng)建類類型對象時由編譯器自動調(diào)用(全自動工具人)
  • 能夠保證每個數(shù)據(jù)成員都有一個合適的初始值,并且在對象的生命周期內(nèi)只調(diào)用一次。

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?構(gòu)造函數(shù)的意義:能夠保證對象被 初始化 (init) 。

構(gòu)造函數(shù)是特殊的成員函數(shù),主要任務(wù)是初始化,而不是開空間(雖然構(gòu)造函數(shù)的名字叫構(gòu)造)。

0x02 構(gòu)造函數(shù)的特性

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?構(gòu)造函數(shù)是特殊的成員函數(shù),主要特征如下:

  • 構(gòu)造函數(shù)的函數(shù)名和類名是相同的 (比如類名是 Date,構(gòu)造函數(shù)名就是 Date)
  • 構(gòu)造函數(shù)無返回值 (它不具有返回類型,因此不能直接返回值)
  • 構(gòu)造函數(shù)支持重載 (仔細(xì)看下面的例子)
  • 會在對象實(shí)例化時自動調(diào)用對象定義出來

比如下面的代碼只需要 Date d1,就會自動調(diào)用構(gòu)造,保證了對象一定是被初始化過的!

"還有這種好事?!"

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)這也太好了吧?我們直接來看看它是怎么用的!?

?? 代碼演示:構(gòu)造函數(shù)的用法 (無參構(gòu)造函數(shù) 和 帶參構(gòu)造函數(shù))

#include <iostream>

class Date {
public:
    /* 無參構(gòu)造函數(shù) */
    Date() {
        _year = 0;
        _month = 1;
        _day = 1;
    }
    /* 帶參構(gòu)造函數(shù) */
    Date(int year, int month, int day) {
        _year = year;
        _month = month;
        _day = day;
    }
    void Print() {
        printf("%d-%d-%d\n", _year, _month, _day);
    }

private:
    int _year;
    int _month;
    int _day;
};

int main(void)
{
    Date d1;   // 對象實(shí)例化,此時觸發(fā)構(gòu)造,調(diào)用無參構(gòu)造函數(shù)
    d1.Print();

    Date d2(2022, 3, 9);   // 對象實(shí)例化,此時觸發(fā)構(gòu)造,調(diào)用帶參構(gòu)造函數(shù)
    d2.Print();

    return 0;
}

?? 運(yùn)行結(jié)果如下:

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

??? 解讀:不給參數(shù)時就會調(diào)用 無參構(gòu)造函數(shù),給參數(shù)則會調(diào)用 帶參構(gòu)造函數(shù)。

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

?? 注意事項:

構(gòu)造函數(shù)是特殊的,不是常規(guī)的成員函數(shù),不能直接調(diào)?c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?。

#include <iostream>

class Date {
public:
    Date(int year = 1, int month = 0, int day = 0) {
        _year = year;
        _month = month;
        _day = day;
    }
private:
    int _year;
    int _month;
    int _day;
};

int main(void)
{
    Date d1;
    d1.Date(); // 不能這么去調(diào),構(gòu)造函數(shù)是特殊的,不是常規(guī)的成員函數(shù)!

    return 0;
}

?? 運(yùn)行結(jié)果:(報錯)

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

如果通過無參構(gòu)造函數(shù)創(chuàng)建對象,對象后面不用跟括號,否則就成了函數(shù)聲明。

#include <iostream>

class Date {
public:
    Date(int year = 1, int month = 0, int day = 0) {
        _year = year;
        _month = month;
        _day = day;
    }
    void Print() {
        printf("%d-%d-%d\n", _year, _month, _day);
    }
private:
    int _year;
    int _month;
    int _day;
};

int main(void)
{
    //帶參這么調(diào):加括號(),在括號中加參數(shù)列表
    Date d2(2022, 3, 9);

    Date d3();   // 這樣可以嗎? 
                 // 既然代參的調(diào)用加括號,在括號中加參數(shù)列表。
                 // 那我不帶參,可不可以加括號呢?
                 ? 仍然不可以。
                 // 這個對象實(shí)際上沒有被定義出來,這里會報錯。 
                 // 編譯器不會識別,所以不傳參數(shù)就老老實(shí)實(shí)地  
                 // Date d3; 不要 Date d3();   
    // 主要是編譯器沒法識別,所以這里記住不能這么干就行了。

    return 0;
}

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

這里如果調(diào)用帶參構(gòu)造函數(shù),我們需要傳遞三個參數(shù)(這里我們沒設(shè)缺?。?。

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

?如果你沒有自己定義構(gòu)造函數(shù)(類中未顯式定義),C++ 編譯器會自動生成一個無參的默認(rèn)構(gòu)造函數(shù)。當(dāng)然,如果你自己定義了,編譯器就不會幫你生成了。

#include <iostream>

class Date {
public:
    /* 如果用戶顯式定義了構(gòu)造函數(shù),編譯器將不再生成
    Date(int year, int month, int day) {
        _year = year;
        _month = month;
        _day = day;
    }
    */
    void Print() {
        printf("%d-%d-%d\n", _year, _month, _day);
    }

private:
    int _year;
    int _month;
    int _day;
};

int main(void)
{
    Date d1;  // 這里調(diào)用的是默認(rèn)生成的無參的構(gòu)造函數(shù)
    d1.Print();

    return 0;
}

?? 運(yùn)行結(jié)果如下:

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

?? 沒有定義構(gòu)造函數(shù),對象也可以創(chuàng)建成功,因此此處調(diào)用的是 編譯器默認(rèn)生成的構(gòu)造函數(shù)。

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

0x03 默認(rèn)構(gòu)造函數(shù)

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?無參構(gòu)造函數(shù)、全缺省構(gòu)造函數(shù)、自動生成的構(gòu)造函數(shù)都被稱為 默認(rèn)構(gòu)造函數(shù)。

并且 默認(rèn)構(gòu)造函數(shù)只能有一個!

class Date {
public:
    /* 全缺省構(gòu)造函數(shù) - 默認(rèn)構(gòu)造函數(shù) */
    Date(int year = 1970, int month = 1, int day = 1) {
        _year = year;
        _month = month;
        _day = day;
    }

private:
    int _year;
    int _month;
    int _day;
};

?? 注意事項:

語法上無參和全缺省可以同時存在,但如果同時存在會引發(fā)二義性:

#include <iostream>

class Date {
public:
    Date() {
        _year = 1970;
        _month = 1;
        _day = 1;
    }
    Date(int year = 1970, int month = 1, int day = 1) {
        _year = year;
        _month = month;
        _day = day;
    }
    
private:
    int _year;
    int _month;
    int _day;
};

int main(void)
{
    Date d1; ?

    return 0;
}

?? 運(yùn)行結(jié)果如下:(報錯)

?? 解讀:無參的構(gòu)造函數(shù)和全缺省的構(gòu)造函數(shù)都成為默認(rèn)構(gòu)造函數(shù),并且默認(rèn)構(gòu)造參數(shù)只能有一個,雖然語法上允許它們們兩個可以同時存在,但是如果有對象定義去調(diào)用就會報錯。

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

?c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?強(qiáng)烈推薦實(shí)現(xiàn)全缺省或者半缺省,因為真的很好用:

#include <iostream>

class Date {
    public:
        /* 全缺省 */
        Date(int year = 0, int month = 1, int day = 1) {
            _year = year;
            _month = month;
            _day = day;
        }
    
        void Print() {
            printf("%d-%d-%d\n", _year, _month, _day);
        } 
    private:
        int _year;
        int _month;
        int _day;
};

int main(void)
{
    Date d1; // 如果不傳,就是缺省值
    Date d2(2022, 1, 15);
    Date d3(2009);
    Date d4(2012, 4);

    d1.Print();  // 0-1-1
    d2.Print();  // 2022-1-15
    d3.Print();  // 2009-1-1
    d4.Print();  // 2012-4-1

    return 0;
}

?? 運(yùn)行結(jié)果如下:

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

0x04 構(gòu)造函數(shù)的特性的測試

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

通過剛才的講解我們知道了任何一個類的默認(rèn)構(gòu)造函數(shù),只有三種:

  • 無參的構(gòu)造函數(shù)
  • 全缺省的構(gòu)造函數(shù)
  • 我們不寫,編譯器自己生成的構(gòu)造函數(shù)

如果你沒有自己定義構(gòu)造函數(shù)(類中未顯式定義),C++ 編譯器會自動生成一個無參的默認(rèn)構(gòu)造函數(shù)。當(dāng)然,如果你自己定義了,編譯器就不會幫你生成了。

?? 代碼演示:讓編譯器自己生成一個

#include <iostream>

class Date {
public:
    // 讓編譯器自己生成一個
    void Print() {
        printf("%d-%d-%d\n", _year, _month, _day);
    }

private:
    int _year;
    int _month;
    int _day;
};

int main(void)
{
    Date d1;  // 這里調(diào)用的是默認(rèn)生成的無參的構(gòu)造函數(shù)
    d1.Print();

    return 0;
}

?? 運(yùn)行結(jié)果如下:

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

?c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?好了,我們來好好探討探討這個問題!

在我們不是先構(gòu)造函數(shù)的情況下,編譯器生成的默認(rèn)構(gòu)造函數(shù)。

"似乎這看起來沒有什么鳥用啊,這不就是一堆隨機(jī)值嘛……"

d1 對象調(diào)用了編譯器生成的默認(rèn)函數(shù),但 d1 對象 year / month / day 依舊是隨機(jī)值,

也就是說這里編譯器生成的默認(rèn)構(gòu)造函數(shù)好像并沒有什么卵用。

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

?? 解答:C++ 把類型分成內(nèi)置類型(基本類型)和自定義類型。

  • 內(nèi)置類型就是語法已經(jīng)定義好的類型:如 int / char...
  • 自定義類型就是我們使用 class / struct / union / 自己定義的類型。

觀察下面的程序,你就會發(fā)現(xiàn)編譯器生成默認(rèn)的構(gòu)造函數(shù),會對自定類型成員?_t?調(diào)用的它的默認(rèn)成員函數(shù):

#include <iostream>
using namespace std;

class Time {
public:
	Time()
	{
		cout << "Time()" << endl;
		_hour = 0;
		_minute = 0;
		_second = 0;
	}
private:
	int _hour;
	int _minute;
	int _second;
};

class Date {
private:
	// 基本類型(內(nèi)置類型)
	int _year;
	int _month;
	int _day;

	// 自定義類型
	Time _t;
};

int main()
{
	Date d;

	return 0;
}

?? 運(yùn)行結(jié)果如下:?

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

?? 測試:對自定義類型處理,會調(diào)用默認(rèn)構(gòu)造函數(shù)(不用參數(shù)就可以調(diào)的函數(shù))

#include<iostream>
using namespace std;

class A {
public:
    // 默認(rèn)構(gòu)造函數(shù)(不用參數(shù)就可以調(diào)的)
    A() {
        cout << " A() " << endl;
        _a = 0;
    }

private:
    int _a;
};

class Date {
public:
private:
    int _year;
    int _month;
    int _day;

    A _aa;   // 對自定義類型處理,此時會調(diào)用默認(rèn)構(gòu)造函數(shù) A() {...}
};

int main(void)
{
    Date d1;

    return 0;
}

?? 運(yùn)行結(jié)果如下:

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

C++?里面把類型分為兩類:內(nèi)置類型(基本類型)和 自定義類型。

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

C++ 規(guī)定:我們不寫?編譯器默認(rèn)生成構(gòu)造函數(shù)對于內(nèi)置類型的成員變量不做初始化處理。

但是對于自定義類型的成員變量會去調(diào)用它的默認(rèn)構(gòu)造函數(shù)(不用參數(shù)就可以調(diào)的)初始化。

如果沒有默認(rèn)構(gòu)造函數(shù)(不用參數(shù)就可以調(diào)用的構(gòu)造函數(shù))就會報錯!

"你要寫就寫好了,要么就別寫,不寫我默認(rèn)生成的能保底"

?? 為了驗證,這里我們故意寫個帶參的默認(rèn)構(gòu)造函數(shù),讓編譯器不默認(rèn)生成:

#include <iostream>
using namespace std;

class A {
public:
    // 如果沒有默認(rèn)的構(gòu)造函數(shù),會報錯。
    A(int a) {    // 故意給個參
        cout << " A() " << endl;
        _a = 0;
    }
private:
    int _a;
};

class Date {
public:
private:
    // 如果沒有默認(rèn)構(gòu)造函數(shù)就會報錯

    int _year;
    int _month;
    int _day;

    A _aa;
};

int main(void)
{
    Date d1;

    return 0;
}

?? 運(yùn)行結(jié)果如下(報錯)

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

?? 我們不寫,讓編譯器默認(rèn)生成一個:

#include<iostream>
using namespace std;

class A {
public:
    // 讓編譯器默認(rèn)生成
private:
    int _a;
};

class Date {
public:
private:
    int _year;
    int _month;
    int _day;

    A _aa;
};

int main(void)
{
    Date d1;

    return 0;
}

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?是隨機(jī)值沒錯,但是這是一種對自定義類型的 "處理",這就是隨機(jī)值的原因?。

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?這里說個題外話,個人認(rèn)為 C++里,我們不寫構(gòu)造函數(shù)編譯器會默認(rèn)生成的這個特性設(shè)計得不好(狗頭保命)……因為沒有對內(nèi)置類型和自定義類型統(tǒng)一處理,不處理內(nèi)置類型成員變量,只處理自定義類型成員變量。

Ⅲ. 析構(gòu)函數(shù)(Destructor)

0x00 引入:專門 “擦屁股” 的析構(gòu)函數(shù)

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?通過前面構(gòu)造函數(shù)的學(xué)習(xí),我們知道了一個對象是怎么來的了,

? 那一個對象又是怎么沒的呢?既然構(gòu)造函數(shù)的本質(zhì)是初始化,那清理的工作交給誰來干呢?

當(dāng)然是交給專門擦屁股的 —— 析構(gòu)函數(shù) (destructor)?!

以前我們玩數(shù)據(jù)結(jié)構(gòu)的時候經(jīng)常忘記調(diào)用 destroy 函數(shù),但是現(xiàn)在我們有析構(gòu)函數(shù)了?。。?/p>

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

(非常炸裂…… 多么振奮人心啊!話不多說讓我們開始講解?。。。?/span>

0x01 析構(gòu)函數(shù)的概念

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?析構(gòu)函數(shù)與構(gòu)造函數(shù)的功能相反。

構(gòu)造函數(shù)是特殊的成員函數(shù),主要任務(wù)是初始化,而不是開空間;

析構(gòu)函數(shù)也一樣,主要任務(wù)是清理,而不是做對象銷毀的工作。

(局部對象銷毀工作是由編譯器完成的)

?? 概念:對象在銷毀時會自動調(diào)用析構(gòu)函數(shù),完成對象的一些資源清理工作。

構(gòu)造函數(shù)和析構(gòu)函數(shù)的名詞翻譯趣談

首先,構(gòu)造函數(shù)的英文是?Constructor,意思為建造者/制造商。析構(gòu)函數(shù)是 Destructor,意思是破壞者/垃圾焚燒爐,誒,這里的垃圾焚燒爐,完成對象的資源清理工作,非常的合理啊。下面我們來看看?"構(gòu)造函數(shù)" 和 "析構(gòu)函數(shù)"?的其他翻譯方式!

[繁] 中國臺灣地區(qū)將 Constructor 翻譯為 "建構(gòu)函式",表示建造和構(gòu)成,Destructor 翻譯為 "解構(gòu)函式",意思應(yīng)該是 "解除構(gòu)造" 的意思。

[韓] 韓語翻譯的就有意思了,本人在韓國留學(xué),這邊的 Constructor 叫? ??? (生成者) Destructor 叫???? (消滅者),非常的簡單直白,但一開始在教材上讀到 "消滅者" 的時候一直沒想到說的是析構(gòu)函數(shù),感覺非常中二……? 怎么不叫 ??? (終結(jié)者)?呢?

0x02 析構(gòu)函數(shù)的特性

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?構(gòu)造函數(shù)是特殊的成員函數(shù),主要特征如下:

  • 析構(gòu)函數(shù)名是在類名前面加上字符?c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?
  • 析構(gòu)函數(shù)既沒有參數(shù)也沒有返回值(因為沒有參數(shù),所以也不會構(gòu)成重載問題)
  • 一個類的析構(gòu)函數(shù)有且僅有一個(如果不寫系統(tǒng)會默認(rèn)生成一個析構(gòu)函數(shù))
  • 析構(gòu)函數(shù)在對象生命周期結(jié)束后,會自動調(diào)用。

(和構(gòu)造函數(shù)是對應(yīng)的構(gòu)造函數(shù)是在對象實(shí)例化的時候自動調(diào)用)

?? 代碼演示:為了演示自動調(diào)用,我們來讓析構(gòu)函數(shù)被調(diào)用時 "吱" 一聲:

#include <iostream>
using namespace std;

class Date {
public:
    Date(int year = 1, int month = 0, int day = 0) {
        _year = year;
        _month = month;
        _day = day;
    }
    void Print() {
        printf("%d-%d-%d\n", _year, _month, _day);
    }

    ~Date() {
        // Date 類沒有資源需要清理,所以Date不實(shí)現(xiàn)析構(gòu)函都是可以的
        cout << "~Date() 吱~ " << endl;  // 測試一下,讓他吱一聲
    }

private:
    int _year;
    int _month;
    int _day;
};

int main(void)
{
    Date d1;
    Date d2(2022, 3, 9);

    return 0;
}

?? 運(yùn)行結(jié)果如下:

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

(這里的析構(gòu)順序問題我們下面會講,不要著急)

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)額,之前舉得日期類的例子沒法很好地展示析構(gòu)函數(shù)的 "魅力" ……

就像本段開頭說情景,我們拿 Stack 來舉個例子,這就很貼切了。

我們知道,棧是需要 destroy 清理開辟的內(nèi)存空間的。

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?這里我們讓析構(gòu)函數(shù)來干這個活,簡直美滋滋!

?? 代碼演示:析構(gòu)函數(shù)的用法

#include<iostream>
#include<stdlib.h>
using namespace std;

typedef int StackDataType;
class Stack {
public:
    /* 構(gòu)造函數(shù) - StackInit */
    Stack(int capacity = 4) {  // 這里只需要一個capacity就夠了,默認(rèn)給4(利用缺省參數(shù))
        _array = (StackDataType*)malloc(sizeof(StackDateType) * capacity);
        if (_array == NULL) {
            cout << "Malloc Failed!" << endl;
            exit(-1);
        }
        _top = 0;
        _capacity = capacity;
    }

    /* 析構(gòu)函數(shù) - StackDestroy */
    ~Stack() {   // 這里就用的上析構(gòu)函數(shù)了,我們需要清理開辟的內(nèi)存空間(防止內(nèi)存泄漏)
        free(_array);
        _array = nullptr;
        _top = _capacity = 0;
    }

private:
    int* _array;
    size_t _top;
    size_t _capacity;
};

int main(void)
{
    Stack s1;
    Stack s2(20); // s2 棧 初始capacity給的是20(可以理解為"客制化")

    return 0;
}

?? 解讀:我們在設(shè)置棧的構(gòu)造函數(shù)時,定義容量 capacity 時利用缺省參數(shù)默認(rèn)給個4的容量,這樣用的時候默認(rèn)就是4,如果不想要4可以自己傳。

如此一來,就可以保證了棧被定義出來就一定被初始化,用完后會自動銷毀。以后就不會有忘記調(diào)用 destroy 而導(dǎo)致內(nèi)存泄露的慘案了,這里的析構(gòu)函數(shù)就可以充當(dāng)銷毀的作用。

0x03 析構(gòu)順序問題

?? 先看代碼:這是我們剛才舉的析構(gòu)函數(shù)的例子

class Date {
public:
    Date(int year = 1, int month = 0, int day = 0) {...}
    void Print() {...}

    ~Date() {
        cout << "~Date() 吱~ " << endl;  // 測試一下,讓他吱一聲
    }

private: 
    {...}
};

int main(void)
{
    Date d1;                    // 誰先析構(gòu)?
    Date d2(2022, 3, 9);        

    return 0;
}

? 問一個比較有意思的問題:這個例子中是先析構(gòu) s1 還是先析構(gòu) s2?

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?
或者這么問:打印結(jié)果的兩個吱分別都是誰叫的?

?? 答案:先析構(gòu) s2,再析構(gòu) s1 ;第一個吱是 s2 叫的,第二個吱是 s1 叫的。

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?剛才例子的解析圖上,我就寫著第一個 吱是 d2 的了:

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

因為析構(gòu)的順序在局部的棧中是相反的,棧幀銷毀清理資源時 s2 先清理,然后再清理 s1!

所以 先構(gòu)造的后析構(gòu),后構(gòu)造的先析構(gòu),所以是 d2 先吱。

(不信的話可以去監(jiān)視一下 this 觀察下成員變量)

【2023.9.27 更新】評論區(qū)對于此問題也有不少提問,這里我再做一個補(bǔ)充說明:

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

這兩個問題實(shí)際上都是在問析構(gòu)順序的,只要把這塊知識點(diǎn)搞明白就會很好理解。

0x04?析構(gòu)函數(shù)的特性的測試

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)又到了測試環(huán)節(jié),上號!

我們知道了,如果沒寫析構(gòu)函數(shù)編譯器會自動生成一個。

那默認(rèn)生成的析構(gòu)函數(shù)會做什么事情呢?它會幫我們 destroy 嘛?

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?hhh,哪有這種好事,不能什么都幫你做啊!

我們剛才講了(我們回顧下,串聯(lián)一下知識點(diǎn)):

?? 如果不自己寫構(gòu)造函數(shù),讓編譯器自動生成,那么這個自動生成的 默認(rèn)構(gòu)造函數(shù)

  • 對于 "內(nèi)置類型" 的成員變量:不會做初始化處理。
  • 對于 "自定義類型" 的成員變量:會調(diào)用它的默認(rèn)構(gòu)造函數(shù)(不用參數(shù)就可以調(diào)的)初始化,如果沒有默認(rèn)構(gòu)造函數(shù)(不用參數(shù)就可以調(diào)用的構(gòu)造函數(shù))就會報錯!

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?而我們的析構(gòu)函數(shù)也是這樣的,一個德行!

?? 如果我們不自己寫析構(gòu)函數(shù),讓編譯器自動生成,那么這個 默認(rèn)析構(gòu)函數(shù)

  • 對于 "內(nèi)置類型" 的成員變量:不作處理 (不會幫你清理的.)
  • 對于 "自定義類型" 的成員變量:會調(diào)用它對應(yīng)的析構(gòu)函數(shù) (已經(jīng)仁至義盡了) 。

" 編譯器:哈哈哈,給你默認(rèn)生成個用用就不錯了,你都懶得寫了,不要挑三揀四滴!"

?? 代碼演示:

#include<iostream>
#include<stdlib.h>
using namespace std;
typedef int StackDataType;

class Stack {
public:
    Stack(int capacity = 4) {
        _array = (StackDataType*)malloc(sizeof(int*) * capacity);
        if (_array == NULL) {
            cout << "Malloc Failed!" << endl;
            exit(-1);
        }
        _top = 0;
        _capacity = capacity;
    }
    // ~Stack() {
    //     free(_array);
    //     _array = nullptr;
    //     _top = _capacity = 0;
    // }

private:
    int* _array;
    size_t _top;
    size_t _capacity;
};

int main(void)
{
    Stack s1;
    Stack s2(20);


    return 0;
}

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)難道就不能幫我把這些事都干了嗎?幫我都銷毀掉不就好了?

不不不,舉個最簡單的例子,迭代器,析構(gòu)的時候是不釋放的,因為不需要他來管,

所以默認(rèn)不對內(nèi)置類型處理是正常的,萬一誤殺了怎么辦,對吧。?

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

有人可能又要說了,這么一來默認(rèn)生成的析構(gòu)函數(shù)不就沒有用了嗎?

有用!他對內(nèi)置類型的成員類型不作處理,會在一些情況下非常的有用!

比如說:?兩個棧實(shí)現(xiàn)一個隊列(LeetCode232) ,用 C++ 可以非常的爽。

?? 代碼演示:自定義類型的成員變量調(diào)用它的析構(gòu)函數(shù)

#include <iostream>
using namespace std;

class String {
public:
	String(const char* str = "jack") {
		_str = (char*)malloc(strlen(str) + 1);
		strcpy(_str, str);
	}
	~String() {
		cout << "~String()" << endl;
		free(_str);
	}
private:
	char* _str;
};

class Person {
private:
	String _name;
	int _age;
};

int main()
{
	Person p;

	return 0;
}

?? 運(yùn)行結(jié)果如下:

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

Ⅳ.? 拷貝構(gòu)造函數(shù)(Copy Constructor)

0x00 引入:可以幫我拷貝嗎?可以!

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

我們在創(chuàng)建對象的時候,能不能創(chuàng)建一個與某一個對象一模一樣的新對象呢?

Date d1(2022, 3, 9);    
d1.Print();

Date d2(d1);    // 照著d1的模子做一個d2
d2.Print();

當(dāng)然可以,這時我們就可以用拷貝構(gòu)造函數(shù)。

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

(但是要警惕無窮遞歸,一定要加引用&,這個我們下面重點(diǎn)講解?。?/span>

0x01 拷貝構(gòu)造函數(shù)的概念

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

?? 拷貝構(gòu)造函數(shù):只有單個形參,該形參是對本類類型對象的引用(一般常用 const 修飾),

在用已存在的類類型對象創(chuàng)建新對象時由編譯器自動調(diào)用。

0x02 拷貝構(gòu)造函數(shù)的特性

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)它也是一個特殊的成員函數(shù),所以他符合構(gòu)造函數(shù)的一些特性:

① 拷貝構(gòu)造函數(shù)是構(gòu)造函數(shù)的一個重載形式。函數(shù)名和類名相同,沒有返回值。

② 拷貝構(gòu)造函數(shù)的參數(shù)只有一個,并且 必須要使用引用傳參!

? ? ?c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?使用傳值方式會引發(fā)無窮遞歸調(diào)用!

"拷貝構(gòu)造函數(shù)的引用是必不可少的!"

類名(const 類名& 形參);

?? 代碼演示:拷貝構(gòu)造函數(shù)的用法

#include <iostream>

class Date {
public:
    Date(int year = 0, int month = 1, int day = 1) {
        _year = year;
        _month = month;
        _day = day;
    }

    /* Date d2(d1); */
    Date(Date& d) {         // 這里要用引用,否則就會無窮遞歸下去
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
    void Print() {
        printf("%d-%d-%d\n", _year, _month, _day);
    }

private:
    int _year;
    int _month;
    int _day;
};

int main(void)
{
    Date d1(2022, 3, 9);
    Date d2(d1);          // 拷貝復(fù)制

    // 看看拷貝成功沒
    d1.Print();
    d2.Print();

    return 0;
}

?? 運(yùn)行結(jié)果如下:

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

? 為什么必須使用引用傳參呢?

調(diào)用拷貝構(gòu)造,需要先穿參數(shù),傳值傳參又是一個拷貝構(gòu)造。

調(diào)用拷貝構(gòu)造,需要先穿參數(shù),傳值傳參又是一個拷貝構(gòu)造。

調(diào)用拷貝構(gòu)造,需要先穿參數(shù),傳值傳參又是一個拷貝構(gòu)造。

……

一直在傳參這里出不去了,所以這個遞歸是一個無窮無盡的。

?? 我們來驗證一下:

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

error:?invalid?constructor;?you?probably?meant?'Date?(const?Date&)'

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

這里不是加不加 const 的問題,而是沒有用引用導(dǎo)致的問題。

不用引用,他就會在傳參那無線套娃遞歸,至于為什么我們繼續(xù)往下看。

?? 拷貝構(gòu)造函數(shù)加 const:如果函數(shù)內(nèi)不需要改變,建議把 const 也給它加上!

class Date {
public:
    Date(int year = 0, int month = 1, int day = 1) {
        _year = year;
        _month = month;
        _day = day;
    }

    /* Date d2(d1); */
    Date(const Date& d) {    // 如果內(nèi)部不需要改變,建議加上const
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }

    void Print() {
        printf("%d-%d-%d\n", _year, _month, _day);
    }

private:
    int _year;
    int _month;
    int _day;
};

第一個原因:怕出錯,萬一你一不小心寫反了怎么辦?

/* Date d2(d1); */
Date(Date& d) {
    d._year = _year;
    d._month = _month;
    d._day = _day;
}

這樣會產(chǎn)生一個很詭異的問題,這一個可以被編譯出來的 BUG ,結(jié)果會變?yōu)殡S機(jī)值。

所以,這里加一個 const 就安全多了,這些錯誤就會被檢查出來了。

第二個原因:以后再講,因為涉及一些臨時對象的概念。

???反正,不想深究的話就記?。?span style="background-color:#f9eda6;">如果函數(shù)體內(nèi)不需要改變,建議把 const 加上?就完事了。

"社會上的事情少打聽,拷貝構(gòu)造直接? X(const& x)? 就行了"

0x03 關(guān)于默認(rèn)生成的拷貝構(gòu)造

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?這里比較特殊,我們單獨(dú)領(lǐng)出來講。?

?? 默認(rèn)生成拷貝構(gòu)造:

內(nèi)置類型的成員,會完成按字節(jié)序的拷貝(把每個字節(jié)依次拷貝過去)。

② 自定義類型成員,會再調(diào)用它的拷貝構(gòu)造。

?? 拷貝構(gòu)造我們不寫生成的默認(rèn)拷貝構(gòu)造函數(shù),對于內(nèi)置類型和自定義類型都會拷貝處理。但是處理的細(xì)節(jié)是不一樣的,這個跟構(gòu)造和析構(gòu)是不一樣的!

#include<iostream>
using namespace std;

class Date {
    public:
        Date(int year = 0, int month = 1, int day = 1) {
            _year = year;
            _month = month;
            _day = day;
        }

        // Date(Date& d) {
        //     _year = d._year;
        //     _month = d._month;
        //     _day = d._day;
        // }

        void Print() {
            printf("%d-%d-%d\n", _year, _month, _day);
        } 
    
    private:
        int _year;
        int _month;
        int _day;
};

int main(void)
{
    Date d1(2002, 4, 8);

    // 拷貝復(fù)制
    Date d2(d1);

    // 沒有寫拷貝構(gòu)造,但是也拷貝成功了
    d1.Print();
    d2.Print();

    return 0;
}

?? 運(yùn)行結(jié)果如下:

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

?? 他這和之前幾個不同了,這個他還真給我解決了。

所以為什么要寫拷貝構(gòu)造?寫他有什么意義?沒有什么意義。

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?默認(rèn)生成的一般就夠用了!

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?當(dāng)然,這并不意味著我們都不用寫了,有些情況還是不可避免要寫的

比如實(shí)現(xiàn)棧的時候,棧的結(jié)構(gòu)問題,導(dǎo)致這里如果用默認(rèn)的?拷貝構(gòu)造,會翻車。

按字節(jié)把所有東西都拷過來會產(chǎn)生問題,如果?Stack?st1?拷貝出另一個?Stack?st2(st1)?

會導(dǎo)致他們都指向那塊開辟的內(nèi)存空間,導(dǎo)致他們指向的空間被析構(gòu)兩次,導(dǎo)致程序崩潰

然而問題不止這些……

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?其實(shí)這里的字節(jié)序拷貝是淺拷貝,下面幾章我會詳細(xì)講一下深淺拷貝,這里的深拷貝和淺拷貝先做一個大概的了解。

?? 總結(jié):對于常見的類,比如日期類,默認(rèn)生成的拷貝構(gòu)造能用。但是對于棧這樣的類,默認(rèn)生成的拷貝構(gòu)造不能用。

Ⅴ.? 總結(jié)(構(gòu)造&析構(gòu)&拷貝構(gòu)造)

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)

默認(rèn)成員函數(shù)有六只,本篇只介紹了三只,剩下的我們后面講。

類和對象部分知識很重要,所以我們來做一個簡單的總結(jié) ~

0x00 構(gòu)造函數(shù)?

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)初始化,在對象實(shí)例化時候自動調(diào)用,保證實(shí)例化對象一定被初始化。

構(gòu)造函數(shù)是默認(rèn)成員函數(shù),我們不寫編譯器會自己生成一份,我們寫了編譯器就不會生成。

我們不寫內(nèi)置類型成員變量不處理。

對于內(nèi)置類型成員變量不處理。

對于自定義類型的成員變量會調(diào)用它的默認(rèn)構(gòu)造函數(shù)。

// 我們需要自己實(shí)現(xiàn)構(gòu)造函數(shù)
class Date {
    int _year;
    int _month;
    int _day;
};
        
// 我們不需要自己實(shí)現(xiàn)構(gòu)造函數(shù),默認(rèn)生成的就可以
class MyQueue {
    Stack _pushST;
    Stack _popST;
};

0x01 析構(gòu)函數(shù)

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)?完成對象中自愿的清理。如果類對象需要資源清理,才需要自己實(shí)現(xiàn)析構(gòu)函數(shù)。

析構(gòu)函數(shù)在對象生命周期到了以后自動調(diào)用,如果你正確實(shí)現(xiàn)了析構(gòu)函數(shù),保證了類對象中的資源被清理。

什么時候生命周期到了?如果是局部變量,出了作用域。全局和靜態(tài)變量,整個程序結(jié)束。

我們不寫編譯器會默認(rèn)生成析構(gòu)函數(shù),我們實(shí)現(xiàn)了,編譯器就不會實(shí)現(xiàn)了。

對于內(nèi)置類型成員變量不處理。

對于自定義類型的成員變量會調(diào)用它的析構(gòu)函數(shù)。

// 沒有資源需要清理,不徐需要自己實(shí)現(xiàn)析構(gòu)函數(shù)
class Date {
    int _year;
    int _month;
    int _day;
};

// 需要自己實(shí)現(xiàn)析構(gòu)函數(shù),清理資源。
class Stack {
    int* _a;
    int  _top;
    int  _capacity;
};

0x02 拷貝構(gòu)造

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)使用同類型的對象去初始化實(shí)例對象。

參數(shù)必須是引用!不然會導(dǎo)致無窮遞歸。

如果我們不實(shí)現(xiàn),編譯器會默認(rèn)生成一份默認(rèn)的拷貝構(gòu)造函數(shù)。

默認(rèn)生成的拷貝構(gòu)造:

① 內(nèi)置類型完成按子繼續(xù)的值拷貝。 —— 淺拷貝

② 自定義類型的成員變量,會去調(diào)用它的拷貝構(gòu)造。

// 不需要自己實(shí)現(xiàn),默認(rèn)生成的拷貝構(gòu)造,完成淺拷貝就能滿足需求
class Date {
    int _year;
    int _month;
    int _day;
};

// 需要自己實(shí)現(xiàn),因為默認(rèn)生成的淺拷貝不能滿足需求。
// 我們需要自己實(shí)現(xiàn)深拷貝的拷貝構(gòu)造,深拷貝我們后面會用專門的章節(jié)去講解。        
class Stack {
    int* _a;
    int  _top;
    int  _capacity;
};
#include <iostream>
using namespace std;

class Date {
public:
    Date(int year = 1, int month = 0, int day = 0) {
        _year = year;
        _month = month;
        _day = day;
    }

    void Print() {
        printf("%d-%d-%d\n", _year, _month, _day);
    }

    ~Date() {
        cout << "&Date()" << endl;
    }

private:
    int _year;
    int _month;
    int _day;
};

int main(void)
{
    Date d1;
    d1.Print();

    Date d2(2002);
    d2.Print();

    Date d3(2022, 3);
    d3.Print();

    Date d4(2022, 3, 9);
    d4.Print();

    return 0;
}

??? 運(yùn)行結(jié)果如下:

c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)


??c++構(gòu)造函數(shù)調(diào)用成員函數(shù),C++要笑著學(xué),c++,類,默認(rèn)成員函數(shù)??

?? [ 筆者 ]? ?王亦優(yōu)
?? [ 更新 ]? ?2022.3.15 | 2023.9.27(重制)
? [ 勘誤 ]?? Star丶北辰:拿棧舉例時malloc空間 sizeof 有誤(已修正)
?? [ 聲明 ]? ?由于作者水平有限,本文有錯誤和不準(zhǔn)確之處在所難免,
              本人也很想知道這些錯誤,懇望讀者批評指正!

?? 參考資料?

Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. .

百度百科[EB/OL]. []. https://baike.baidu.com/.

比特科技. C++[EB/OL]. 2021[2021.8.31]文章來源地址http://www.zghlxwxcb.cn/news/detail-724322.html

到了這里,關(guān)于?【C++要笑著學(xué)】(7) 默認(rèn)成員函數(shù):構(gòu)造函數(shù) | 析構(gòu)函數(shù) | 拷貝構(gòu)造函數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包