深入理解C++賦值構造函數的實現原理

一、賦值構造函數是什麼

在C++中,如果我們定義一個類,它裡面包含有指針成員變量時,需要特別注意這個指針的生命周期和對象的生命周期,確保在對象被銷毀前,指針指向的內存已經被釋放,否則可能會發生內存泄漏等問題。而賦值構造函數就是用來實現對象的深度複製,解決因為指針成員變量導致的這類問題。


class Test{
public:
    Test():data(nullptr), len(0) {}
    ~Test(){
        if(data != nullptr)
            delete[] data;
    }
    Test(const Test& t){
        if(t.data != nullptr){
            this->data = new int[t.len];
            memcpy(this->data, t.data, sizeof(int)*t.len);
            this->len = t.len;
        }
    }
    Test& operator=(const Test& t){
        if(this == &t) return *this;
        if(this->data != nullptr) delete[] data;
        if(t.data != nullptr){
            this->data = new int[t.len];
            memcpy(this->data, t.data, sizeof(int)*t.len);
            this->len = t.len;
        }
        return *this;
    }
private:
    int* data;
    int len;
};

二、淺拷貝和深拷貝的區別

在實現賦值構造函數之前,我們需要先了解一下淺拷貝和深拷貝的概念。

所謂淺拷貝,是將對象的所有成員變量的值都複製給新對象,包括指針成員變量的地址值,也就是說,新對象和原對象共享指針指向的內存。這樣,當其中一個對象釋放指針指向的內存時,另一個對象的指針也就變成了野指針,這很容易導致內存管理的問題。

而深拷貝則是將指針指向的內存也進行複製,這樣新對象和原對象互不影響,互相獨立,即便其中一個對象釋放了指針指向的內存,也不會影響另一個對象。

三、實現賦值構造函數

在實現賦值構造函數前,我們需要重載賦值運算符。下面是一個示例代碼:


Test& operator=(const Test& t){
    if(this == &t) return *this;
    if(this->data != nullptr) delete[] data;
    if(t.data != nullptr){
        this->data = new int[t.len];
        memcpy(this->data, t.data, sizeof(int)*t.len);
        this->len = t.len;
    }
    return *this;
}

需要注意的是,在重載賦值運算符中,需要進行自我賦值的判斷。如果不進行判斷的話,當對象自己賦值給自己時,就會導致指針指向的內存多次刪除,這會導致程序崩潰。因此,我們需要在賦值前判斷是否是自我賦值,如果是,則直接返回對象自身。

然後便可以進行賦值操作了。首先,需要刪除原先數據指針指向的內存。然後,需要重新分配內存,並將原始數據拷貝到新分配的內存區域中。最後,返回當前對象的引用。


if(this->data != nullptr) delete[] data;
if(t.data != nullptr){
    this->data = new int[t.len];
    memcpy(this->data, t.data, sizeof(int)*t.len);
    this->len = t.len;
}
return *this;

四、測試賦值構造函數的實現原理

下面是一個用於測試的代碼,首先我們定義了一個類Test, 其中包含有一個指針類型成員變量data,用於存儲int類型的數組,另一個成員變量len表示數組的長度。然後分別使用構造函數和賦值構造函數進行初始化,並可以通過輸出打印數組的值,來驗證賦值構造函數的實現原理。


#include <iostream>

using namespace std;

class Test{
public:
    Test():data(nullptr), len(0) {}
    ~Test(){
        if(data != nullptr)
            delete[] data;
    }
    Test(const Test& t){
        if(t.data != nullptr){
            this->data = new int[t.len];
            memcpy(this->data, t.data, sizeof(int)*t.len);
            this->len = t.len;
        }
    }
    Test& operator=(const Test& t){
        if(this == &t) return *this;
        if(this->data != nullptr) delete[] data;
        if(t.data != nullptr){
            this->data = new int[t.len];
            memcpy(this->data, t.data, sizeof(int)*t.len);
            this->len = t.len;
        }
        return *this;
    }
    
    void printData(){
        cout << "==========" << endl;
        for(int i = 0; i < len; ++i){
            cout << data[i] << " ";
        }
        cout << endl << "==========" << endl;
    }

private:
    int* data;
    int len;
};

int main(){
    Test t1;
    t1.len = 3;
    t1.data = new int[t1.len];
    t1.data[0] = 1;
    t1.data[1] = 2;
    t1.data[2] = 3;
    t1.printData();

    Test t2 = t1;
    t2.printData();

    Test t3;
    t3 = t1;
    t3.printData();
    
    return 0;
}

運行結果如下:


========== 
1 2 3 
========== 
========== 
1 2 3 
========== 
========== 
1 2 3 
========== 

我們可以看到,三個Test對象的值均相等,通過輸出來證明賦值構造函數的實現原理是正確的。

五、總結

賦值構造函數是用於處理類中存在指針成員變量時進行賦值的構造函數,保證對象間的獨立性,以及在釋放指針指向的內存時的正確性。需要注意的是,在實現賦值構造函數時,需要判斷是否自我賦值。並且,為了保證賦值操作的有效性,需要將原先的指針指向的內存進行刪除,並重新分配內存,並將原先的數據拷貝到新分配的內存區域中。

原創文章,作者:JATV,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/138263.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
JATV的頭像JATV
上一篇 2024-10-04 00:19
下一篇 2024-10-04 00:19

相關推薦

  • Python中引入上一級目錄中函數

    Python中經常需要調用其他文件夾中的模塊或函數,其中一個常見的操作是引入上一級目錄中的函數。在此,我們將從多個角度詳細解釋如何在Python中引入上一級目錄的函數。 一、加入環…

    編程 2025-04-29
  • Python中capitalize函數的使用

    在Python的字符串操作中,capitalize函數常常被用到,這個函數可以使字符串中的第一個單詞首字母大寫,其餘字母小寫。在本文中,我們將從以下幾個方面對capitalize函…

    編程 2025-04-29
  • Python中set函數的作用

    Python中set函數是一個有用的數據類型,可以被用於許多編程場景中。在這篇文章中,我們將學習Python中set函數的多個方面,從而深入了解這個函數在Python中的用途。 一…

    編程 2025-04-29
  • 三角函數用英語怎麼說

    三角函數,即三角比函數,是指在一個銳角三角形中某一角的對邊、鄰邊之比。在數學中,三角函數包括正弦、餘弦、正切等,它們在數學、物理、工程和計算機等領域都得到了廣泛的應用。 一、正弦函…

    編程 2025-04-29
  • 單片機打印函數

    單片機打印是指通過串口或並口將一些數據打印到終端設備上。在單片機應用中,打印非常重要。正確的打印數據可以讓我們知道單片機運行的狀態,方便我們進行調試;錯誤的打印數據可以幫助我們快速…

    編程 2025-04-29
  • Python3定義函數參數類型

    Python是一門動態類型語言,不需要在定義變量時顯示的指定變量類型,但是Python3中提供了函數參數類型的聲明功能,在函數定義時明確定義參數類型。在函數的形參後面加上冒號(:)…

    編程 2025-04-29
  • Python實現計算階乘的函數

    本文將介紹如何使用Python定義函數fact(n),計算n的階乘。 一、什麼是階乘 階乘指從1乘到指定數之間所有整數的乘積。如:5! = 5 * 4 * 3 * 2 * 1 = …

    編程 2025-04-29
  • Python定義函數判斷奇偶數

    本文將從多個方面詳細闡述Python定義函數判斷奇偶數的方法,並提供完整的代碼示例。 一、初步了解Python函數 在介紹Python如何定義函數判斷奇偶數之前,我們先來了解一下P…

    編程 2025-04-29
  • Harris角點檢測算法原理與實現

    本文將從多個方面對Harris角點檢測算法進行詳細的闡述,包括算法原理、實現步驟、代碼實現等。 一、Harris角點檢測算法原理 Harris角點檢測算法是一種經典的計算機視覺算法…

    編程 2025-04-29
  • 分段函數Python

    本文將從以下幾個方面詳細闡述Python中的分段函數,包括函數基本定義、調用示例、圖像繪製、函數優化和應用實例。 一、函數基本定義 分段函數又稱為條件函數,指一條直線段或曲線段,由…

    編程 2025-04-29

發表回復

登錄後才能評論