1. 程式人生 > >建構函式,拷貝建構函式,解構函式,賦值函式

建構函式,拷貝建構函式,解構函式,賦值函式

例一:

class CGoods
{
    //行為,成員方法
public:
    CGoods(char *name = NULL, int amount = 0, double price = 0.0) //建構函式
    {
        if (name == NULL)
        {
            mpName = new char[1];
            *mpName = '\0';
        } 
        else
        {
            mpName = new char[strlen(name) + 1];
            strcpy(mpName, name);
        }
        
        mAmount = amount;
        mPrice = price;
    }
    ~CGoods()        //解構函式


    {
        delete[]mpName;
        mpName = NULL;
    }
    CGoods(const CGoods &src)              //拷貝建構函式
    {
        mpName = new char[strlen(src.mpName) + 1];
        strcpy(mpName, src.mpName);
        mAmount = src.mAmount;
        mPrice = src.mPrice;
    }
    void operator=(const CGoods &src)      //賦值函式

    {
        if (this == &src)
            return;

        delete[]mpName;
        mpName = NULL;

        mpName = new char[strlen(src.mpName) + 1];
        strcpy(mpName, src.mpName);
        mAmount = src.mAmount;
        mPrice = src.mPrice;
    }
private:
    char *mpName;
    int mAmount;
    double mPrice;
};

建構函式

        沒有返回值、函式名字和類名稱必須一樣
        建構函式可以帶引數,因此建構函式可以過載
        當沒有提供任何建構函式的時候,編譯器會給類提供預設的建構函式,函式什麼也不做,是個空函式

解構函式

       沒有返回值  不能帶引數  不能過載

拷貝建構函式

      拷貝建構函式不能按值傳遞!!!

     把形參複製到實參會呼叫拷貝建構函式。如果允許拷貝建構函式傳值,就會在拷貝建構函式內呼叫拷貝建構函式,形成永無休止的遞迴呼叫從而導致棧滿溢位。只能將建構函式修改為A(const A&other),即把傳值引數改為常量引用(傳指標也不可以,只能改為引用

      用物件初始化物件,預設做的拷貝方式是,按記憶體位元組拷貝過去,俗稱淺拷貝!
      如果物件佔用了外部的資源,那麼預設的淺拷貝一定會發生問題的!所以,當預設的淺拷貝發生問題的時候,需要使用者自己提供相應的拷貝建構函式

如果物件預設的淺拷貝發生問題,那麼有哪些解決方案?
    1。提供自定義的拷貝建構函式和賦值運算子的過載函式
    2。把拷貝建構函式和賦值運算子的過載函式的宣告提供在private裡面

賦值函式

賦值步驟:

1,先排除自賦值;2,釋放原來的資源;3,重新開闢空間,賦值

例二:

OOP的迴圈佇列構造,析構,拷貝構造,賦值函式

class CQueue
{
public:

CQueue(int size = 10)              //建構函式
    {
        mFront = mRear = 0;
        mSize = size;
        mpQueue = new int[mSize];
    }

CQueue(const CQueue &src)               //拷貝建構函式
    {
        cout << "CQueue(const CQueue &src)" << endl;
        mFront = src.mFront;
        mRear = src.mRear;
        mSize = src.mSize;
        mpQueue = new int[mSize];
        for (int i = mFront; i != mRear; i = (i + 1) % mSize)
        {
            mpQueue[i] = src.mpQueue[i];
        }
    }

void operator=(const CQueue &src)          //賦值函式
    {
        cout << "operator=" << endl;
        // 先排除自賦值
        if (this == &src)
        {
            return;
        }
        //釋放原來的資源
        delete []mpQueue;
        mpQueue = NULL;
        //重新開闢空間,賦值
        mFront = src.mFront;
        mRear = src.mRear;
        mSize = src.mSize;
        mpQueue = new int[mSize];
        for (int i = mFront; i != mRear; i = (i + 1) % mSize)
        {
            mpQueue[i] = src.mpQueue[i];
        }
    }

~CQueue()                            //解構函式
    {
        delete[]mpQueue;
        mpQueue = NULL;
    }

/*CQueue queue1 ;  //queue1被初始化為queue,queue1析構後地址被釋放,queue指向變為野指標*/

/*對於物件的運算  =》   左邊物件呼叫成員方法,把右邊的物件當做引數傳入
    queue2.operator=(queue1);
    void operator=(const CQueue &src) */

物件的構造和析構:

    1.物件的生成分兩步  
    a.給物件分配記憶體   b.呼叫建構函式構造物件  =》 物件產生了!!!

    2.如果沒有提供任何建構函式,編譯器會產生預設建構函式,空函式;但是如果使用者提供
    了任意建構函式,編譯器就不再產生預設構造函數了!

    3.在呼叫預設建構函式的時候,不要新增()

    4.棧上的物件,先構造,後析構;後構造,先析構

    5.棧上的物件,定義的時候呼叫相應的建構函式;return處,要析構棧上的所有物件

例三:

class String
{
public:
    String(const char*str = NULL)     //普通建構函式
    {
        if (str == NULL)
        {
            m_data = new char[1];
            *m_data = 0;
        }
        else
        {
            m_data = new char[strlen(str) + 1];
            strcpy(m_data, str);
        }
    }
    String(const String&other)   //拷貝建構函式
    {
        m_data = new char[strlen(other.m_data) + 1];
        strcpy(m_data,other.m_data);
    }
    ~String()                 //解構函式
    {
        delete[]m_data;
        m_data = NULL;
    }
    String &operator = (const String &other)     //賦值函式
    {
        if (this == &other)
        {
            return *this;
        }
        delete[]&m_data;
        m_data = NULL;
        m_data = new char[strlen(other.m_data) + 1];
        strcpy(m_data, other.m_data);
    }
    
private:
    char*m_data;
};
 

其他:

int *p = new int; //分配int整形大小的空間
int *p = new int();//分配int整形大小的空間並初始化0
int *p = new int(10);//分配int整形大小的空間並初始化10
int *p = new int[10];   只開闢記憶體,10個大小為int整形的空間,不進行初始化
int *p = new int[10]();  不僅僅開闢記憶體,而且還初始化,int,陣列所有元素的初值為0

用臨時物件,拷貝構造新物件,此時臨時物件就被C++編譯器優化掉了

物件使用的三個優化規則:
1.函式引數傳遞物件,用引用傳遞,不要按值傳遞
2.如果你的函式返回的是物件的值,請返回一個臨時物件,不要返回一個
已經存在的物件
3.接收返回物件的函式,以初始化方式接收,不要用賦值方式接收