亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C++修煉之拷貝構(gòu)造函數(shù)

 更新時間:2023年04月03日 08:41:48   作者:花想云  
這篇文章主要內(nèi)容是6個默認成員函數(shù)之一的拷貝構(gòu)造函數(shù)的認識與學習,讓同學們充分理解淺拷貝與深拷貝,感興趣的小伙伴可以參考閱讀

??文章導讀

本章主要內(nèi)容為6個默認成員函數(shù)之一的拷貝構(gòu)造函數(shù)的認識與學習,充分理解淺拷貝與深拷貝。

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

還記得上一章中提到的6個默認成員函數(shù)嗎?當我們定義好一個類,不做任何處理時,編譯器會自動生成以下6個默認成員函數(shù)

  • 默認成員函數(shù):如果用戶沒有手動實現(xiàn),則編譯器會自動生成的成員函數(shù)。

同樣,拷貝構(gòu)造函數(shù)也屬于6個默認成員函數(shù),而且拷貝構(gòu)造函數(shù)構(gòu)造函數(shù)的一種重載形式。

  • 拷貝構(gòu)造函數(shù)的功能就如同它的名字——拷貝。我們可以用一個已存在的對象來創(chuàng)建一個與已存在對象一模一樣的新的對象。

??舉例??

class Date
{
public:
    //構(gòu)造函數(shù)
    Date()
    {
        cout << "Date()" << endl;
    }
    //拷貝構(gòu)造函數(shù)
    Date(const Date& d)
    {
        cout << "Date()" << endl;
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
    //析構(gòu)函數(shù)
    ~Date()
    {
        cout << "~Date()" << endl;
    }
private:
    int _year = 0;
    int _month = 0;
    int _day = 0;
};

void TestDate()
{
    Date d1;
    //調(diào)用拷貝構(gòu)造創(chuàng)建對象
    Date d2(d1);
}

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

拷貝構(gòu)造函數(shù)作為特殊的成員函數(shù)同樣也有異于常人的特性:

  1. 拷貝構(gòu)造函數(shù)是構(gòu)造函數(shù)的重載;
  2. 拷貝構(gòu)造函數(shù)的參數(shù)只有一個且必須是類類型對象的引用。若使用傳值的方式,則編譯器會報錯,因為理論上這會引發(fā)無窮遞歸。

??錯誤示例??

class Date
{
public:
    //錯誤示例
    //如果這樣寫,編譯器就會直接報錯,但我們現(xiàn)在假設(shè)如果編譯器不會檢查,
    //這樣的程序執(zhí)行起來會發(fā)生什么
    Date(const Date d)
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }
private:
    int _year = 0;
    int _month = 0;
    int _day = 0;
};
void TestDate()
{
    Date d1;
    //調(diào)用拷貝構(gòu)造創(chuàng)建對象
    Date d2(d1);
}
  • 當拷貝構(gòu)造函數(shù)的參數(shù)采用傳值的方式時,創(chuàng)建對象d2,會調(diào)用它的拷貝構(gòu)造函數(shù),d1會作為實參傳遞給形參d。不巧的是,實參傳遞給形參本身又是一個拷貝,會再次調(diào)用形參的拷貝構(gòu)造函數(shù)…如此便會引發(fā)無窮的遞歸。

  1. 若未顯式定義,編譯器會生成默認的拷貝構(gòu)造函數(shù)。 默認的拷貝構(gòu)造函數(shù)對象按內(nèi)存存儲按字節(jié)序完成拷貝,這種拷貝叫做淺拷貝或者值拷貝;

??舉例??

class Date
{
public:
    //構(gòu)造函數(shù)
    Date(int year = 0, int month = 0, int day = 0)
    {
        //cout << "Date()" << endl;
        _year = year;
        _month = month;
        _day = day;
    }
    //未顯式定義拷貝構(gòu)造函數(shù)
    /*Date(const Date& d)
    {
        _year = d._year;
        _month = d._month;
        _day = d._day;
    }*/
    void print()
    {
        cout << _year << " - " << _month << " - " << _day << endl;
    }
private:
    int _year = 0;
    int _month = 0;
    int _day = 0;
};

void TestDate()
{
    Date d1(2023, 3, 31);
    //調(diào)用拷貝構(gòu)造創(chuàng)建對象
    Date d2(d1);
    d2.print();
}

  • 有的小伙伴可能會有疑問:編譯器默認生成的拷貝構(gòu)造函數(shù)貌似可以很好的完成任務,那么還需要我們手動來實現(xiàn)嗎?
    答案是:當然需要。Date類只是一個較為簡單的類且類成員都是內(nèi)置類型,可以不需要。但是當類中含有自定義類型時,編譯器可就辦不了事兒了。
  1. 類中如果沒有涉及資源申請時,拷貝構(gòu)造函數(shù)是否寫都可以;一旦涉及到資源申請時,則拷貝構(gòu)造函數(shù)是一定要寫的,否則就是淺拷貝;

??錯誤示例??

class stack
{
public:
    stack(int defaultCapacity=10)
    {
        _a = (int*)malloc(sizeof(int)*defaultCapacity);
        if (_a == nullptr)
        {
            perror("malloc fail");
            exit(-1);
        }
        _top =  0;
        _capacity = defaultCapacity;
    }
    ~stack()
    {
        cout << "~Stack()" << endl;
        free(_a);
        _a = nullptr;
        _top = _capacity = 0;
    }
    void push(int n)
    {
        _a[_top++] = n;
    }
    void print()
    {
        for (int i = 0; i < _top; i++)
        {
            cout << _a[i] << " ";
        }
        cout << endl;
    }
private:
    int* _a;
    int _top;
    int _capacity;
};

void TestStack()
{
    stack s1;
    s1.push(1);
    s1.push(2);
    s1.push(3);
    s1.push(4);
    s1.print();

    stack s2(s1);
    s2.print();
    s2.push(5);
    s2.push(6);
    s2.push(7);
    s2.push(8);
    s2.print();
}

如圖所示,這段程序的運行結(jié)果是程序崩潰了,且通過觀察發(fā)現(xiàn),是在第二次析構(gòu)時出現(xiàn)了錯誤。其實出現(xiàn)錯誤的原因是在第二次析構(gòu)時對野指針進行free了。

??一個小tip??

  • 多個對象進行析構(gòu)的順序如同一樣,先創(chuàng)建的對象后析構(gòu),后創(chuàng)建的對象先析構(gòu)。

為什么會出現(xiàn)對野指針進行free呢?

  • 原因是,對象s1與對象s2中的成員_a,指向的是同一塊空間。在s2析構(gòu)完成后,這塊空間已經(jīng)被釋放,此時的s1._a就是野指針。這就是淺拷貝導致的后果。

??理解淺拷貝??

編譯器默認生成的拷貝構(gòu)造函數(shù)是按字節(jié)序拷貝的,在創(chuàng)建s2對象時,僅僅是把s1._a的值賦值給s2._a,并沒有重新開辟一塊與s1._a所指向的空間大小相同內(nèi)容相同的空間。我們把前者的拷貝方式稱為淺拷貝,后者稱為深拷貝

當開啟監(jiān)視窗口來觀察這一過程,我們可以看到s2在進行push時,s1的內(nèi)容也在跟著改變,且s1._a=s2._a

??正確的做法??

class stack
{
public:
    stack(int defaultCapacity=10)
    {
        _a = (int*)malloc(sizeof(int)*defaultCapacity);
        if (_a == nullptr)
        {
            perror("malloc fail");
            exit(-1);
        }
        _top =  0;
        _capacity = defaultCapacity;
    }
    //用戶自己定義拷貝構(gòu)造函數(shù)
    stack(const stack& s)
    {
        _a= (int*)malloc(sizeof(int) * s._capacity);
        if (_a == nullptr)
        {
            perror("malloc fail");
            exit(-1);
        }

        memcpy(_a, s._a, sizeof(int) * s._capacity);
        _top = s._top;
        _capacity = s._capacity;
    }
    ~stack()
    {
        cout << "~Stack()" << endl;
        free(_a);
        _a = nullptr;
        _top = _capacity = 0;
    }
    void push(int n)
    {
        _a[_top++] = n;
    }
    void print()
    {
        for (int i = 0; i < _top; i++)
        {
            cout << _a[i] << " ";
        }
        cout << endl;
    }
private:
    int* _a;
    int _top;
    int _capacity;
};
  1. 拷貝構(gòu)造函數(shù)典型調(diào)用場景
  • 使用已存在對象創(chuàng)建新對象;
  • 函數(shù)參數(shù)類型為類類型對象;
  • 函數(shù)返回值類型為類類型對象。

為了提高程序效率,一般對象傳參時,盡量使用引用類型,返回時根據(jù)實際場景,能用引用盡量使用引用

本章的內(nèi)容到這里就結(jié)束了,下一章我們將學習運算符重載與取地址操作符的重載~ 覺得內(nèi)容有用的話就支持一下吧~

到此這篇關(guān)于C++修煉之拷貝構(gòu)造函數(shù)的文章就介紹到這了,更多相關(guān)C++拷貝構(gòu)造函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Qt掃盲篇之QRegExp正則匹配類總結(jié)

    Qt掃盲篇之QRegExp正則匹配類總結(jié)

    這篇文章主要給大家介紹了關(guān)于Qt掃盲篇之QRegExp正則匹配類總結(jié)的相關(guān)資料,QRegExp是Qt框架中的一個類,用于進行正則表達式的匹配和處理,它提供了多種模式來匹配不同的字符串,需要的朋友可以參考下
    2023-12-12
  • 關(guān)于win32 gettimeofday替代方案

    關(guān)于win32 gettimeofday替代方案

    下面小編就為大家?guī)硪黄P(guān)于win32 gettimeofday替代方案。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • C++矩陣運算的實現(xiàn)簡單

    C++矩陣運算的實現(xiàn)簡單

    本文主要介紹了C++矩陣運算的實現(xiàn)簡單,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • C++實現(xiàn)LeetCode(160.求兩個鏈表的交點)

    C++實現(xiàn)LeetCode(160.求兩個鏈表的交點)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(160.求兩個鏈表的交點),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C語言sizeof和strlen的指針和數(shù)組面試題詳解

    C語言sizeof和strlen的指針和數(shù)組面試題詳解

    strlen是函數(shù),字符串長度,不包括停止符。而sizeof則是內(nèi)存塊的大小,包括停止符。數(shù)組是一種數(shù)據(jù)類型,數(shù)據(jù)類型的本質(zhì)就是固定大小,內(nèi)存塊的別名??梢杂胹izeof()一般都是數(shù)據(jù)類型
    2022-04-04
  • C語言實現(xiàn)簡單酒店管理系統(tǒng)

    C語言實現(xiàn)簡單酒店管理系統(tǒng)

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)簡單酒店管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C++ 智能指針的魅力你都了解嗎

    C++ 智能指針的魅力你都了解嗎

    智能指針使用和普通指針類似。解引用一個智能指針返回它指向的對象。如果在一個條件判斷中使用智能指針,效果就是檢測它是否為空,本文給大家介紹C++ 智能指針的相關(guān)知識,感興趣的朋友一起看看吧
    2021-06-06
  • C語言數(shù)組的各種操作梳理

    C語言數(shù)組的各種操作梳理

    數(shù)組是一組有序的數(shù)據(jù)的集合,數(shù)組中元素類型相同,由數(shù)組名和下標唯一地確定,數(shù)組中數(shù)據(jù)不僅數(shù)據(jù)類型相同,而且在計算機內(nèi)存里連續(xù)存放,地址編號最低的存儲單元存放數(shù)組的起始元素,地址編號最高的存儲單元存放數(shù)組的最后一個元素
    2022-04-04
  • C++實現(xiàn)簡單掃雷游戲

    C++實現(xiàn)簡單掃雷游戲

    這篇文章主要為大家詳細介紹了C++實現(xiàn)簡單掃雷游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • c++特殊構(gòu)造函數(shù)詳解

    c++特殊構(gòu)造函數(shù)詳解

    大家好,本篇文章主要講的是c++特殊構(gòu)造函數(shù)詳解,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2022-01-01

最新評論