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;
}
總結:: 物件不存在,且沒用別的物件來初始化,呼叫建構函式
物件不存在,且用別的物件來初始化,呼叫拷貝構造
物件存在,用別的物件給他賦值,就是賦值函式