1. 程式人生 > 其它 >C++封裝 之 拷貝建構函式

C++封裝 之 拷貝建構函式

拷貝建構函式

思考

  • 拷貝建構函式的定義?
  • 什麼時候呼叫拷貝建構函式?
  • 拷貝建構函式如何實現?

拷貝建構函式回顧:

  • 定義
    拷貝建構函式與普通建構函式基本相同,只是引數上有嚴格要求:(1)要加const ;(2)傳入的是引用,且是一個物件;

  • 如果沒有自定義拷貝建構函式,系統會自動生成一個預設的拷貝建構函式。

  • 當採用直接初始化(Student st1)或複製初始化(Student st2=st1 或Student st2(st3) )例項化物件時,系統自動呼叫拷貝建構函式;

  • 函式呼叫傳遞引數時也會呼叫拷貝建構函式。

  • 拷貝建構函式的引數是確定的,不能過載。

淺拷貝 和 深拷貝

  • 只是將資料成員的值進行了簡單的拷貝,稱為淺拷貝
  • 不僅僅是做值的拷貝,堆中記憶體也要拷貝,稱為深拷貝

例項1(淺拷貝)

定義一個Array類

  • 資料成員為m_iCount ,
  • 成員函式包括建構函式、拷貝建構函式、解構函式、資料封裝函式
  • 通過此示例體會淺拷貝原理
copy_demo1.cpp原始碼:
#include<iostream>
#include<stdlib.h>
using namespace std;
/****************** 定義Array類 ******************************/
class Array{
public:
    Array();
    Array(const Array &arr);    //拷貝建構函式定義
    ~Array();
    void setCount(int count);
    int getCount();
private:
    int m_iCount;
};
/****************** Array類的函式實現 ******************************/
Array::Array(){
    cout << "Array()" << endl;
}
Array::Array(const Array &arr){  //拷貝建構函式實現
    m_iCount = arr.m_iCount;
    cout << "Array &" << endl;
}
Array::~Array(){
    cout << "~Array()" << endl;
}
void Array::setCount(int count){
    m_iCount = count;
}
int Array::getCount(){
    return m_iCount;
}
/****************** 測試主函式 ******************************/
int main(){
    Array arr1;
    arr1.setCount(9);
    cout << "arr1.m_iCount = "<< arr1.getCount() << endl;

    Array arr2(arr1);  // 用arr1拷貝例項化arr2,呼叫拷貝建構函式
    cout << "arr2.m_iCount = "<<arr2.getCount() << endl;

    system("pause");
    return 0;
}
執行結果:
Array()
arr1.m_iCount = 9
Array &
arr2.m_iCount = 9

例項2(深拷貝)

  • 增加資料成員m_pArr
  • 並增加m_pArr地址檢視函式,同時改造建構函式、拷貝建構函式和解構函式,
  • 通過此示例體會淺拷貝原理
copy_demo2.cpp原始碼
#include<iostream>
#include<stdlib.h>
using namespace std;
/****************** 定義Array類 ******************************/
class Array{
public:
    Array(int count);
    Array(const Array &arr);    //拷貝建構函式定義
    ~Array();
    void setCount(int count);
    int getCount();
    void printAddr();          //資料成員*m_pArr的封裝函式,列印地址
    void printArr();           //列印m_pArr所指向地址的值
private:
    int m_iCount;
    int *m_pArr;                //增加資料成員*m_pArr
};
/****************** Array類的函式實現 ******************************/
Array::Array(int count){
    m_iCount = count;
    m_pArr = new int[m_iCount];   //前提是m_iCount是一個確切的值,所以建構函式要傳入一個引數count
    for(int i=0; i<m_iCount; i++) //賦值(為了方便列印)
        m_pArr[i] = i;
    cout << "Array()" << endl;
}
/*
Array::Array(const Array &arr){  //拷貝建構函式實現(淺拷貝)
    m_pArr = arr.m_pArr;         //兩個指標指向同一塊記憶體(理論上是錯誤的)
    m_iCount = arr.m_iCount;
    cout << "Array &" << endl;
}
*/
Array::Array(const Array &arr){    //拷貝建構函式實現(深拷貝)
    m_iCount = arr.m_iCount;        
    m_pArr = new int[m_iCount];     //先給當前指標分配記憶體
    for(int i=0; i<m_iCount; ++i){  //再做記憶體拷貝
        m_pArr[i] = arr.m_pArr[i]; 
    }
    cout << "Array &" << endl;
}

Array::~Array(){
    delete []m_pArr;             //
    m_pArr = NULL;               //
    cout << "~Array()" << endl;
}
void Array::setCount(int count){
    m_iCount = count;
}
int Array::getCount(){
    return m_iCount;
}

void Array::printAddr(){         ///
    cout << "m_pArr point to " << m_pArr << endl;
}

void Array::printArr(){
    for(int i=0; i<m_iCount; i++)
        cout<<"m_pArr["<<i<<"] = "<< m_pArr[i]<<endl;
}
/****************** 測試主函式 ******************************/
int main(){
    Array arr1(9);
    Array arr2(arr1);  // 用arr1拷貝例項化arr2,呼叫拷貝建構函式,使用深拷貝之後,兩個指標指向不同記憶體地址
    //arr1.setCount(9);    //建構函式中已經傳入了引數9,所以不需要arr1.setCount(9)了

    arr1.printAddr();
    arr2.printAddr();    //兩個指標會指向同一塊記憶體,同一塊記憶體不能釋放兩遍,兩個物件都執行解構函式就會發生執行時錯誤

    arr1.printArr();
    arr2.printArr();

    system("pause");
    return 0;
}

執行結果:
Array()
Array &
m_pArr point to 0x711920
m_pArr point to 0x711960
m_pArr[0] = 0
m_pArr[1] = 1
m_pArr[2] = 2
m_pArr[3] = 3
m_pArr[4] = 4
m_pArr[5] = 5
m_pArr[6] = 6
m_pArr[7] = 7
m_pArr[8] = 8
m_pArr[0] = 0
m_pArr[1] = 1
m_pArr[2] = 2
m_pArr[3] = 3
m_pArr[4] = 4
m_pArr[5] = 5
m_pArr[6] = 6
m_pArr[7] = 7
m_pArr[8] = 8