- C++ 基礎
- C++ 首頁
- C++ 概述
- C++ 環境搭建
- C++ 基本語法
- C++ 註釋
- C++ Hello World
- C++ 省略名稱空間
- C++ 常量/字面量
- C++ 關鍵字
- C++ 識別符號
- C++ 資料型別
- C++ 數值資料型別
- C++ 字元資料型別
- C++ 布林資料型別
- C++ 變數型別
- C++ 變數作用域
- C++ 多個變數
- C++ 基本輸入/輸出
- C++ 修飾符型別
- C++ 儲存類
- C++ 運算子
- C++ 數字
- C++ 列舉
- C++ 引用
- C++ 日期和時間
- C++ 控制語句
- C++ 決策
- C++ if 語句
- C++ if else 語句
- C++ 巢狀 if 語句
- C++ switch 語句
- C++ 巢狀 switch 語句
- C++ 迴圈型別
- C++ while 迴圈
- C++ for 迴圈
- C++ do while 迴圈
- C++ foreach 迴圈
- C++ 巢狀迴圈
- C++ break 語句
- C++ continue 語句
- C++ goto 語句
- C++ 建構函式
- C++ 建構函式和解構函式
- C++ 複製建構函式
C++ 複製建構函式
複製建構函式
複製建構函式是一個建構函式,它透過用之前建立的同一類的物件初始化來建立物件。複製建構函式用於:
- 從另一個相同型別的物件初始化一個物件。
- 複製一個物件以將其作為引數傳遞給函式。
- 複製一個物件以從函式返回它。
如果在類中沒有定義複製建構函式,編譯器本身會定義一個。如果類具有指標變數並進行了一些動態記憶體分配,則必須有一個複製建構函式。
語法
複製建構函式最常見的形式如下所示:
classname (const classname &obj) {
// body of constructor
}
這裡,obj 是一個對正在用於初始化另一個物件的物件的引用。
複製建構函式示例
以下示例演示了複製建構函式的使用
#include <iostream>
using namespace std;
class Line {
public:
int getLength( void );
Line( int len ); // simple constructor
Line( const Line &obj); // copy constructor
~Line(); // destructor
private:
int *ptr;
};
// Member functions definitions including constructor
Line::Line(int len) {
cout << "Normal constructor allocating ptr" << endl;
// allocate memory for the pointer;
ptr = new int;
*ptr = len;
}
Line::Line(const Line &obj) {
cout << "Copy constructor allocating ptr." << endl;
ptr = new int;
*ptr = *obj.ptr; // copy the value
}
Line::~Line(void) {
cout << "Freeing memory!" << endl;
delete ptr;
}
int Line::getLength( void ) {
return *ptr;
}
void display(Line obj) {
cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main() {
Line line(10);
display(line);
return 0;
}
當以上程式碼編譯並執行時,會產生以下結果:
Normal constructor allocating ptr Copy constructor allocating ptr. Length of line : 10 Freeing memory! Freeing memory!
複製建構函式建立新物件
您可以透過複製建構函式的概念,使用現有物件建立一個新物件。
在以下示例中,複製建構函式用於建立一個作為現有物件副本的新物件。
示例
讓我們看看同一個示例,但稍作修改,使用相同型別的現有物件建立另一個物件:
#include <iostream>
using namespace std;
class Line {
public:
int getLength( void );
Line( int len ); // simple constructor
Line( const Line &obj); // copy constructor
~Line(); // destructor
private:
int *ptr;
};
// Member functions definitions including constructor
Line::Line(int len) {
cout << "Normal constructor allocating ptr" << endl;
// allocate memory for the pointer;
ptr = new int;
*ptr = len;
}
Line::Line(const Line &obj) {
cout << "Copy constructor allocating ptr." << endl;
ptr = new int;
*ptr = *obj.ptr; // copy the value
}
Line::~Line(void) {
cout << "Freeing memory!" << endl;
delete ptr;
}
int Line::getLength( void ) {
return *ptr;
}
void display(Line obj) {
cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main() {
Line line1(10);
Line line2 = line1; // This also calls copy constructor
display(line1);
display(line2);
return 0;
}
當以上程式碼編譯並執行時,會產生以下結果:
Normal constructor allocating ptr Copy constructor allocating ptr. Copy constructor allocating ptr. Length of line : 10 Freeing memory! Copy constructor allocating ptr. Length of line : 10 Freeing memory! Freeing memory! Freeing memory!
隱式與顯式複製建構函式
在 C++ 中,有兩種型別的複製建構函式,即隱式和顯式。這裡我們將討論這兩者之間的區別。
隱式複製建構函式
如果使用者沒有定義自己的複製建構函式,則編譯器會自動提供一個隱式複製建構函式。它執行物件的淺複製,這意味著它將物件的每個成員的值複製到新物件。
何時呼叫隱式複製建構函式?
- 當用戶按值將物件傳遞給函式時。
- 當用戶從函式按值返回物件時。
- 當用戶用相同型別的另一個物件初始化物件時(複製初始化)。
顯式(使用者定義)複製建構函式
它是使用者定義的建構函式。這使您可以訪問自定義複製行為,例如建立深複製而不是預設的淺複製。
示例
以下是 C++ 中顯式和隱式複製建構函式的示例
#include <iostream>
using namespace std;
class MyClass {
private:
int value;
public:
// Constructor
MyClass(int v) : value(v) {}
// Explicit Copy Constructor
MyClass(const MyClass& other) : value(other.value) {
cout << "Explicit Copy Constructor called" << endl;
}
void display() const { cout << "Value: " << value << endl; }
};
void processValue(MyClass obj) {
// Implicit copy constructor will be called here
obj.display();
}
int main() {
MyClass obj1(10); // Constructor called
MyClass obj2 = obj1; // Explicit copy constructor called
obj1.display();
obj2.display();
processValue(obj1); // Implicit copy constructor called
return 0;
}
當以上程式碼編譯並執行時,會產生以下結果:
Explicit Copy Constructor called Value: 10 Value: 10 Explicit Copy Constructor called Value: 10
三法則/五法則
三法則和五法則建議在定義複製建構函式 (ClassName(const ClassName& other)) 時,也應定義
三法則和五法則建議在定義**複製建構函式**(ClassName(const ClassName& other)) 時,也應定義
- 三法則
- **解構函式**(~ClassName())**。**
- 以及**複製賦值運算子**(ClassName& operator=(const ClassName& other)),以確保正確管理記憶體**。**
- 五法則
- **移動建構函式**(ClassName(ClassName&& other))。
- **移動賦值運算子**(ClassName& operator=(ClassName&& other))”。
這些特殊成員函式對於正確管理動態記憶體和其他資源(如檔案處理或網路連線)在類中是必要的。
深複製與淺複製
在 C++ 中,深複製和淺複製是複製物件的兩種不同方式,當類涉及動態記憶體管理時,它們非常重要。
1. 淺複製
當以這樣一種方式複製物件時,原始物件和複製物件共享相同的資源,就會發生淺複製。這意味著複製建構函式或複製賦值運算子僅複製資料成員(如指標)的值,而不會分配新的記憶體或建立資源的獨立副本。
示例
#include <iostream>
using namespace std;
class MyClass {
private:
int* data; // Pointer to an integer
public:
// Constructor
MyClass(int value) {
data = new int(value); // Allocate memory
}
// Shallow Copy Constructor
MyClass(const MyClass& other) {
data = other.data; // Copy pointer only
}
// Destructor
~MyClass() {
delete data; // Free memory
}
// Display the value
void showData() const { cout << "Data: " << *data << endl; }
};
int main() {
MyClass obj1(42); // Create an object
MyClass obj2 = obj1; // Use shallow copy constructor
obj1.showData();
obj2.showData();
return 0;
}
當以上程式碼編譯並執行時,會產生以下結果:
Data: 42 Data: 42 free(): double free detected in tcache 2
2. 深複製
當透過為其自身資源的副本分配新記憶體來複制物件時,就會發生深複製,確保原始物件和複製物件完全獨立。避免雙重釋放錯誤或懸空指標。
示例
#include <iostream>
using namespace std;
class MyClass {
private:
int* data; // Pointer to an integer
public:
// Constructor: Dynamically allocate memory
// and initialize with value
MyClass(int value) { data = new int(value); }
// Deep Copy Constructor
// Allocates new memory and copies the value
MyClass(const MyClass& other) { data = new int(*other.data); }
// Destructor to clean up memory
~MyClass() { delete data; }
// Display the value
void showData() const { cout << "Data: " << *data << endl; }
};
int main() {
MyClass obj1(42); // Create an object
MyClass obj2 = obj1; // Use deep copy constructor
obj1.showData(); // Display data from obj1
obj2.showData(); // Display data from obj2
return 0;
}
當以上程式碼編譯並執行時,會產生以下結果:
Data: 42 Data: 42