一、什麼是構造函數與析構函數
在C++中,對象的創建和銷毀都是由構造函數和析構函數控制的。構造函數是在對象創建時被調用,用於初始化對象的屬性和數據成員;析構函數則是在對象銷毀時被調用,用於清理對象佔用的資源。
構造函數和析構函數是類的成員函數,沒有返回值,函數名必須與類名相同。一個類可以有多個構造函數,但只能有一個析構函數。
下面是一個簡單的示例代碼:
class Person { public: Person() { // 默認構造函數 name = ""; age = 0; std::cout << "Person對象被創建" <name = name; this->age = age; std::cout << "Person對象被創建" << std::endl; } ~Person() { // 析構函數 std::cout << "Person對象被銷毀" << std::endl; } private: std::string name; int age; };
二、構造函數
構造函數可以分為默認構造函數和有參構造函數。默認構造函數不帶任何參數,用於創建對象時對數據成員進行默認初始化。有參構造函數則接收參數,在創建對象時進行屬性的初始化。
下面是一個默認構造函數和有參構造函數的示例代碼:
class Person { public: Person() { // 默認構造函數 name = ""; age = 0; } Person(std::string name, int age) { // 有參構造函數 this->name = name; this->age = age; } private: std::string name; int age; }; int main() { Person p1; // 調用默認構造函數 Person p2("Tom", 20); // 調用有參構造函數 return 0; }
需要注意的是,如果一個類定義了有參構造函數,那麼默認構造函數不會被自動創建。如果需要使用默認構造函數,就必須自己定義。
另外,可以使用初始化列表來對數據成員進行初始化,這樣效率更高,代碼也更簡潔。下面是初始化列表的示例代碼:
class Person { public: Person() : name(""), age(0) {} // 初始化列表 Person(std::string name, int age) : name(name), age(age) {} private: std::string name; int age; };
三、析構函數
析構函數是對象銷毀時自動被調用的函數,用於清理對象使用的資源,如動態分配的內存空間、打開的文件等。
下面是一個示例代碼,展示在何時調用析構函數:
class Person { public: Person() { std::cout << "Person對象被創建" << std::endl; } ~Person() { std::cout << "Person對象被銷毀" << std::endl; } }; int main() { Person p1; // 調用構造函數,輸出 "Person對象被創建" { Person p2; // 調用構造函數,輸出 "Person對象被創建" } // 調用析構函數,輸出 "Person對象被銷毀" return 0; // 調用析構函數,輸出 "Person對象被銷毀" }
可以看到,當一個對象的作用域結束時,其析構函數就會被調用。在上面的示例代碼中,p2的作用域在{}中,當{}結束時,p2就會被銷毀。
四、拷貝構造函數
拷貝構造函數是用於在創建一個對象時,以已經存在的對象作為初始化來源。拷貝構造函數可以通過傳遞引用或指針的方式進行調用。
如果我們沒有定義拷貝構造函數,C++會為我們生成一個默認的拷貝構造函數。但是如果類中包含了動態分配的內存空間時,需要我們手動定義拷貝構造函數,以確保正確地複製對象。
下面是一個手動定義拷貝構造函數的示例代碼:
class Person { public: Person() { } Person(std::string name, int age) : name(name), age(age) { } Person(const Person& p) { // 拷貝構造函數 name = p.name; age = p.age; } private: std::string name; int age; }; int main() { Person p1("Tom", 20); Person p2(p1); // 調用拷貝構造函數 return 0; }
五、移動構造函數和移動賦值運算符
移動構造函數和移動賦值運算符是C++11引入的新特性。它們的作用是將一個對象的資源轉移到另一個對象中,避免了對象的拷貝,提高了程序的效率。
移動構造函數用於在創建一個對象時將另一個對象的資源“移動”到新對象中;移動賦值運算符用於將一個對象的資源“移動”到另一個對象中。移動構造函數和移動賦值運算符都可以通過右值引用的方式進行調用。
下面是一個示例代碼,展示如何使用移動構造函數和移動賦值運算符:
class Vector { public: Vector() : data(nullptr), size(0) {} Vector(const Vector& other) { // 拷貝構造函數 size = other.size; data = new int[size]; for (int i = 0; i < size; i++) { data[i] = other.data[i]; } } Vector(Vector&& other) { // 移動構造函數 data = other.data; size = other.size; other.data = nullptr; other.size = 0; } Vector& operator=(const Vector& other) { // 拷貝賦值運算符 delete[] data; size = other.size; data = new int[size]; for (int i = 0; i < size; i++) { data[i] = other.data[i]; } return *this; } Vector& operator=(Vector&& other) { // 移動賦值運算符 delete[] data; data = other.data; size = other.size; other.data = nullptr; other.size = 0; return *this; } private: int* data; size_t size; }; int main() { Vector v1; Vector v2 = std::move(v1); // 使用移動構造函數 Vector v3; v3 = std::move(v2); // 使用移動賦值運算符 return 0; }
總結
本文介紹了C++中的構造函數和析構函數,以及其一些衍生的概念如拷貝構造函數和移動構造函數。掌握這些概念有助於我們更好地理解C++中對象的初始化和清理過程,並編寫高效、安全的代碼。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/295269.html