溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++中的拷貝構造函數(shù)怎么用

發(fā)布時間:2022-02-14 09:31:40 來源:億速云 閱讀:122 作者:小新 欄目:開發(fā)技術

小編給大家分享一下C++中的拷貝構造函數(shù)怎么用,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

    C++拷貝構造函數(shù)(復制構造函數(shù))詳解

    拷貝和復制是一個意思,對應的英文單詞都是copy。對于計算機來說,拷貝是指用一份原有的、已經(jīng)存在的數(shù)據(jù)創(chuàng)建出一份新的數(shù)據(jù),最終的結果是多了一份相同的數(shù)據(jù)。例如,將 Word 文檔拷貝到U盤去復印店打印,將 D 盤的圖片拷貝到桌面以方便瀏覽,將重要的文件上傳到百度網(wǎng)盤以防止丟失等,都是「創(chuàng)建一份新數(shù)據(jù)」的意思。

    在 C++ 中,拷貝并沒有脫離它本來的含義,只是將這個含義進行了“特化”,是指用已經(jīng)存在的對象創(chuàng)建出一個新的對象。從本質(zhì)上講,對象也是一份數(shù)據(jù),因為它會占用內(nèi)存。

    嚴格來說,對象的創(chuàng)建包括兩個階段,首先要分配內(nèi)存空間,然后再進行初始化:

    分配內(nèi)存很好理解,就是在堆區(qū)、棧區(qū)或者全局數(shù)據(jù)區(qū)留出足夠多的字節(jié)。這個時候的內(nèi)存還比較“原始”,沒有被“教化”,它所包含的數(shù)據(jù)一般是零值或者隨機值,沒有實際的意義。

    初始化就是首次對內(nèi)存賦值,讓它的數(shù)據(jù)有意義。注意是首次賦值,再次賦值不叫初始化。初始化的時候還可以為對象分配其他的資源(打開文件、連接網(wǎng)絡、動態(tài)分配內(nèi)存等),或者提前進行一些計算(根據(jù)價格和數(shù)量計算出總價、根據(jù)長度和寬度計算出矩形的面積等)等。說白了,初始化就是調(diào)用構造函數(shù)。

    很明顯,這里所說的拷貝是在初始化階段進行的,也就是用其它對象的數(shù)據(jù)來初始化新對象的內(nèi)存。

    那么,如何用拷貝的方式來初始化一個對象呢?其實這樣的例子比比皆是,string 類就是一個典型的例子。

    #include <iostream>
    #include <string>
    using namespace std;
    void func(string str){
        cout<<str<<endl;
    }
    int main(){
        string s1 = "http://c.ttt.net";
        string s2(s1);
        string s3 = s1;
        string s4 = s1 + " " + s2;
        func(s1);
        cout<<s1<<endl<<s2<<endl<<s3<<endl<<s4<<endl;
       
        return 0;
    }
    運行結果:
    http://c.ttt.net
    http://c.ttt.net
    http://c.ttt.net
    http://c.ttt.net
    http://c.ttt.net http://c.ttt.net

    s1、s2、s3、s4 以及 func() 的形參 str,都是使用拷貝的方式來初始化的。
    對于 s1,表面上看起來是將一個字符串直接賦值給了 s1,實際上在內(nèi)部進行了類型轉換,將 const char * 類型轉換為 string 類型后才賦值的。s4 也是類似的道理。

    對于 s1、s2、s3、s4,都是將其它對象的數(shù)據(jù)拷貝給當前對象,以完成當前對象的初始化。

    對于 func() 的形參 str,其實在定義時就為它分配了內(nèi)存,但是此時并沒有初始化,只有等到調(diào)用 func() 時,才會將其它對象的數(shù)據(jù)拷貝給 str 以完成初始化。

    當以拷貝的方式初始化一個對象時,會調(diào)用一個特殊的構造函數(shù),就是拷貝構造函數(shù)(Copy Constructor)。

    下面的例子演示了拷貝構造函數(shù)的定義和使用:

    #include <iostream>
    #include <string>
    using namespace std;
    class Student{
    public:
        Student(string name = "", int age = 0, float score = 0.0f);  //普通構造函數(shù)
        Student(const Student &stu);  //拷貝構造函數(shù)(聲明)
    public:
        void display();
    private:
        string m_name;
        int m_age;
        float m_score;
    };
    Student::Student(string name, int age, float score): m_name(name), m_age(age), m_score(score){ }
    //拷貝構造函數(shù)(定義)
    Student::Student(const Student &stu){
        this->m_name = stu.m_name;
        this->m_age = stu.m_age;
        this->m_score = stu.m_score;
       
        cout<<"Copy constructor was called."<<endl;
    }
    void Student::display(){
        cout<<m_name<<"的年齡是"<<m_age<<",成績是"<<m_score<<endl;
    }
    int main(){
        Student stu1("小明", 16, 90.5);
        Student stu2 = stu1;  //調(diào)用拷貝構造函數(shù)
        Student stu3(stu1);  //調(diào)用拷貝構造函數(shù)
        stu1.display();
        stu2.display();
        stu3.display();
       
        return 0;
    }

    運行結果:

    Copy constructor was called.
    Copy constructor was called.
    小明的年齡是16,成績是90.5
    小明的年齡是16,成績是90.5
    小明的年齡是16,成績是90.5

    第 8 行是拷貝構造函數(shù)的聲明,第 20 行是拷貝構造函數(shù)的定義??截悩嬙旌瘮?shù)只有一個參數(shù),它的類型是當前類的引用,而且一般都是 const 引用。

    1) 為什么必須是當前類的引用呢?

    如果拷貝構造函數(shù)的參數(shù)不是當前類的引用,而是當前類的對象,那么在調(diào)用拷貝構造函數(shù)時,會將另外一個對象直接傳遞給形參,這本身就是一次拷貝,會再次調(diào)用拷貝構造函數(shù),然后又將一個對象直接傳遞給了形參,將繼續(xù)調(diào)用拷貝構造函數(shù)&hellip;&hellip;這個過程會一直持續(xù)下去,沒有盡頭,陷入死循環(huán)。

    只有當參數(shù)是當前類的引用時,才不會導致再次調(diào)用拷貝構造函數(shù),這不僅是邏輯上的要求,也是 C++ 語法的要求。

    2) 為什么是 const 引用呢?

    拷貝構造函數(shù)的目的是用其它對象的數(shù)據(jù)來初始化當前對象,并沒有期望更改其它對象的數(shù)據(jù),添加 const 限制后,這個含義更加明確了。

    另外一個原因是,添加 const 限制后,可以將 const 對象和非 const 對象傳遞給形參了,因為非 const 類型可以轉換為 const 類型。如果沒有 const 限制,就不能將 const 對象傳遞給形參,因為 const 類型不能轉換為非 const 類型,這就意味著,不能使用 const 對象來初始化當前對象了。

    以上面的 Student 類為例,將 const 去掉后,拷貝構造函數(shù)的原型變?yōu)椋?br/>Student::Student(Student &stu);

    此時,下面的代碼就會發(fā)生錯誤:

    const Student stu1("小明", 16, 90.5);
    Student stu2 = stu1;
    Student stu3(stu1);

    stu1 是 const 類型,在初始化 stu2、stu3 時,編譯器希望調(diào)用Student::Student(const Student &stu),但是這個函數(shù)卻不存在,又不能將 const Student 類型轉換為 Student 類型去調(diào)用Student::Student(Student &stu),所以最終調(diào)用失敗了。

    當然,你也可以再添加一個參數(shù)為 const 引用的拷貝構造函數(shù),這樣就不會出錯了。換句話說,一個類可以同時存在兩個拷貝構造函數(shù),一個函數(shù)的參數(shù)為 const 引用,另一個函數(shù)的參數(shù)為非 const 引用。

    默認拷貝構造函數(shù)

    在前面的教程中,我們還沒有講解拷貝構造函數(shù),但是卻已經(jīng)在使用拷貝的方式創(chuàng)建對象了,并且也沒有引發(fā)什么錯誤。這是因為,如果程序員沒有顯式地定義拷貝構造函數(shù),那么編譯器會自動生成一個默認的拷貝構造函數(shù)。這個默認的拷貝構造函數(shù)很簡單,就是使用“老對象”的成員變量對“新對象”的成員變量進行一一賦值,和上面 Student 類的拷貝構造函數(shù)非常類似。

    對于簡單的類,默認拷貝構造函數(shù)一般是夠用的,我們也沒有必要再顯式地定義一個功能類似的拷貝構造函數(shù)。但是當類持有其它資源時,如動態(tài)分配的內(nèi)存、打開的文件、指向其他數(shù)據(jù)的指針、網(wǎng)絡連接等,默認拷貝構造函數(shù)就不能拷貝這些資源,我們必須顯式地定義拷貝構造函數(shù),以完整地拷貝對象的所有數(shù)據(jù)。

    以上是“C++中的拷貝構造函數(shù)怎么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業(yè)資訊頻道!

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

    c++
    AI