1. 程式人生 > >c++ 拷貝函式和賦值函式的區別

c++ 拷貝函式和賦值函式的區別

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

1.建構函式

建構函式:: 當建立一個類的物件時,它被呼叫來對**類的資料成員進行初始化和記憶體分配**
對於c++的空類,編譯器預設加入以下成員函式
1.預設建構函式
2.拷貝建構函式
3.解構函式
4.賦值函式(賦值運算子)

**************ATTENTION::***********
建構函式可以被過載(過載::函式名相同,引數不同)
解構函式只有一個,不能被過載,不帶引數

2.拷貝建構函式

拷貝構造::一種特殊的建構函式,用基於同一類的一個物件構造和初始化另一個物件。
當沒有拷貝建構函式時,通過預設拷貝建構函式來建立一個物件。
A a;
A b(a);
A b= a;
都是拷貝建構函式來建立物件b
*************ATTENTION******************


b 物件之前是不存在的,用a物件來構造和初始化b的!!!

何時呼叫拷貝建構函式
1. 物件以值傳遞的方式傳入函式內
2. 物件以值傳遞的方式從函式返回
3. 物件需要通過另一個物件初始化

引入一個問題

#include <iostream>
using namespace std;
class Test {
    int i;
public:
    Test(int x) {
        i = x;
    }
    Test(const Test& a) {
        this->i = a.i;
        cout << "Copy"
<< endl; } }; Test work() { Test tot(0); return tot; } /*Test work() { Test* tot = new Test(1); return *tot; }*/ int main() { work(); return 0; }

該段程式碼— 物件以值傳遞的方式從函式返回
在debug版本下z——————能走到拷貝建構函式中
在release版本下z—————-不能走到拷貝建構函式

*****************************REASON*************************


copy elision 拷貝省略**,在這裡也叫具名返回值優化(named return value optimization),詳情厚度一下就行了。

VS的debug時一般不作該優化,所以會有拷貝;release時就會優化,沒有拷貝,直接構造,原因自然是debug和release的編譯優化配置不同。**

什麼時候編譯器生成預設的拷貝建構函式
1.使用者未自定義,程式碼中卻用到
2.使用者定義建構函式,未定義拷貝建構函式,程式碼中用到

******************ATTENTION****************************
**系統預設提供的拷貝建構函式的工作方式是記憶體拷貝—淺拷貝。
如果物件中用到了需要手動釋放的物件,就會出現問題,這時就需要手動過載拷貝建構函式—–實現深拷貝**

淺拷貝: 如果複製的物件中引用以一個外部內容(例如分配在堆上的資料),那麼在複製這個物件的時候,讓新舊物件指向同一個外部內容,就是淺拷貝。(指標雖然複製了,但所指向的空間內容並沒有複製,而是由兩個物件共用,兩個物件不獨立,刪除弓箭存在問題)

深拷貝:如果在複製這個物件的時候為新物件製作了外部物件的獨立複製,就是深拷貝。

拷貝建構函式過載宣告 A(const A& other)

3.賦值函式

賦值函式:: 一個類的物件向該類的另一個物件賦值。

當沒有過載賦值函式(賦值運算子)時,通過預設賦值函式來進行賦值操作。
A a;
A b;
b =a ;
********************ATTENTION***************************
a, b 物件是已經存在的,用a物件來賦值給b!!!!!!

賦值運算子的過載宣告:
A& operator = (const A& other)

拷貝建構函式和賦值函式的區別

1.拷貝建構函式是一個物件初始化一塊記憶體區域,這塊記憶體就是新物件的記憶體去,而賦值函式是對於一個已經被初始化的物件進行賦值操作。

2。在資料成員包含指標物件的時候,一種是複製指標物件,另一種是引用指標物件。拷貝建構函式大多數是複製,賦值函式是引用物件。

3。實現不一樣。拷貝–是建構函式,通過引數物件,初始化產生一個物件。賦值函式則把一個新的物件賦值給一個原有的物件——所有如果原有的物件中有記憶體分配要先把記憶體釋放掉,而且還要檢查一下兩個物件是不是同一個物件,如果是,不做任何操作,直接返回

!!!!不想寫拷貝構造和賦值函式,有不允許編譯器自動生成,
最簡單——將這兩個函式宣告為私有函式。

string 類的完成的3個函式實現

#include <string>
class string
{
    string(const char* str);
    string(const string& ohter);
    string& operator=(const string& other);
    ~string();
private:
    char* m_data;
};
// 建構函式
string::string(const char* str)
{
    if(str == NULL)
    {
        m_data = new char[1];
        m_data = '\n';
    }
    else
    {
        int strlen = strlen(str);
        m_data = new char[strlen + 1];
        strcpy(m_data, str);
    }
}
// 拷貝建構函式
string::string(const string& other)
{
    int strlen = strlen(other.m_data);
    m_data = new char[strlen +1];
    strcpy(m_data , other.m_data);
}
//賦值函式
string & string::operator=(const string& other)
{
    if(this == &other) //自我檢查
    {
        return *this;
    }
    //刪除原有資料記憶體
    delete []m_data;
    int strlen = strlen(other.m_data);
    m_data = new char[strlen +1];
    strcpy(m_data ,other.m_data);
    return 8this;
}
// 解構函式
string::~string()
{
    delete []m_data;
}

總結:: 物件不存在,且沒用別的物件來初始化,呼叫建構函式
物件不存在,且用別的物件來初始化,呼叫拷貝構造
物件存在,用別的物件給他賦值,就是賦值函式