一、結構函數簡介
結構函數(構造函數)是一個特殊的成員函數,主要作用是在創建對象時對其進行初始化操作。在C++中,每個類可以擁有一個或多個結構函數,且結構函數名稱與類名稱相同,沒有返回值類型,可以有參數或不帶參數。當對象被創建時,結構函數會自動調用,完成對象的初始化工作。
class Person { public: Person() { name = "Unknown"; age = 0; } Person(string n, int a) { name = n; age = a; } private: string name; int age; };
上述代碼定義了一個Person類,並定義了兩個結構函數。第一個結構函數不帶參數,用於默認初始化name為「Unknown」、age為0;第二個結構函數帶有兩個參數,用於指定類成員的值。在創建Person對象時,就會自動調用結構函數進行初始化。
二、結構函數分類
C++結構函數可分為默認結構函數、拷貝結構函數、移動結構函數和轉換結構函數等幾種類型。
1. 默認結構函數
在類中沒有定義結構函數時,編譯器會自動生成一個默認結構函數。如果不需要自定義結構函數,可以直接使用默認結構函數。
class Person { public: string name; int age; }; Person p; // 調用默認結構函數初始化
2. 拷貝結構函數
拷貝結構函數用於在對象之間進行賦值或參數傳遞時調用。拷貝結構函數有兩種形式:
a) 淺拷貝結構函數:成員變數逐一進行複製,指針成員變數仍指向同一內存地址。
class Person { public: Person(int a, char* n) { age = a; name = new char[strlen(n)+1]; strcpy(name, n); } Person(const Person &p) { // 拷貝結構函數 age = p.age; name = p.name; // 淺拷貝,指針成員變數仍指向同一地址 } ~Person() { delete[] name; // delete釋放new申請的內存 } private: char* name; int age; }; Person p1(18, "Tom"); Person p2 = p1; // 調用拷貝結構函數
在上述代碼中,用new動態申請了一段內存來存儲類成員name的值。在拷貝結構函數中,進行了淺拷貝,即將指針成員變數直接複製,不重新分配內存。這樣會導致p1和p2的name指針變數都指向同一塊內存地址,造成內存重複釋放問題。
b) 深拷貝結構函數:對指針成員變數進行新的內存分配,複製值到新的內存空間中。
class Person { public: Person(int a, char* n) { age = a; name = new char[strlen(n)+1]; strcpy(name, n); } Person(const Person &p) { // 拷貝結構函數 age = p.age; name = new char[strlen(p.name)+1]; // 深拷貝,重新分配內存 strcpy(name, p.name); } ~Person() { delete[] name; // delete釋放new申請的內存 } private: char* name; int age; }; Person p1(18, "Tom"); Person p2 = p1; // 調用拷貝結構函數
在上述代碼中,在拷貝結構函數中重新分配了一段新的內存空間,將原指針成員變數的值複製到新的空間中,避免了內存重複釋放問題。
3. 移動結構函數
移動結構函數用於在對象之間進行賦值操作時調用,且源對象的資源不需要保留。在移動結構函數中,首先進行資源的交換,然後將源對象的資源清空。
class Person { public: Person(int a, string n) { age = a; name = n; } Person(Person &&p) { // 移動結構函數 age = p.age; name = p.name; p.name = ""; // 清空源對象的資源 } private: string name; int age; }; Person p1(18, "Tom"); Person p2 = move(p1); // 調用移動結構函數
在上述代碼中,使用move()函數調用了移動結構函數,進行資源的移動和清空。
4. 轉換結構函數
轉換函數(類型轉換函數)用於將一個類類型對象轉換為另一個類型的對象,可以使用顯示或隱式類型轉換。轉換結構函數沒有返回值類型,名稱和類名稱相同,可以有或沒有參數。
三、結構函數的特殊條件
1. 虛擬結構函數
虛擬結構函數(虛構造函數)是一個聲明為虛擬的結構函數。在一個繼承關係的類中,當通過指針或引用調用一個虛擬結構函數時,會自動調用最適當的版本,即最終派生類實現的版本。使用虛擬結構函數的主要目的是實現運行時多態。
class Person { public: virtual ~Person() {} // 定義虛擬結構函數 }; class Student : public Person { public: ~Student() {} }; Person* p = new Student(); // 使用指針調用虛擬結構函數 delete p; // 調用最終派生類的析構函數
在上述代碼中,定義了一個虛擬結構函數,在派生類中重新定義了析構函數。在創建Student對象時,使用指針訪問虛擬結構函數,當釋放內存時,自動調用最終派生類Student的析構函數。
2. 純虛擬結構函數
純虛擬結構函數(純虛構造函數)是一個沒有實現的虛擬結構函數,其目的是在基類中定義一個介面,強制派生類必須實現該介面。在定義純虛擬結構函數時,需要在結構函數後面加上「= 0」,表示沒有實現該函數。不能直接創建一個純虛擬結構函數的對象。
class Person { public: virtual void show() = 0; }; class Student : public Person { public: void show() { cout << "I am a student." <show(); delete p;
在上述代碼中,定義了一個純虛擬結構函數show(),在派生類Student中實現了該函數。在創建Student對象時,使用指針調用show()函數。
四、結構函數的應用
1. 對象間的依賴關係
結構函數可以用於在創建對象時,對對象之間的依賴關係進行設置。
class Person { public: Person() { t = new Time(0, 0, 0); } void setTime(int h, int m, int s) { t->setTime(h, m, s); } private: Time* t; }; class Time { public: Time(int h, int m, int s) { hour = h; minute = m; second = s; } void setTime(int h, int m, int s) { hour = h; minute = m; second = s; } private: int hour; int minute; int second; };
在上述代碼中,創建了一個Person類和一個Time類,在Person類中創建了一個Time對象的指針t,並在結構函數中對其進行初始化。在Person類中還定義了一個設置時間的函數,通過t指針間接訪問Time對象,並設置時間。這樣就形成了一個Person對象和一個Time對象之間的依賴關係。
2. 繼承的應用
結構函數的重載和繼承可用於強制派生類對基類成員進行初始化或重新定義。
class Base { public: Base(int a) { num = a; } virtual void show() { cout << "Base: " << num << endl; } private: int num; }; class Son : public Base { public: Son(int a, int b) : Base(a) { // 調用基類結構函數進行初始化 age = b; } void show() { cout << "Son: " << age << endl; } private: int age; };
在上述代碼中,定義了一個基類Base和一個派生類Son。在派生類結構函數中通過冒號(:)調用基類結構函數對基類成員num進行初始化,以保證基類成員的正確性。在派生類中重新定義了show()函數,對基類函數進行了覆蓋,實現了多態效果。
五、結構函數的注意事項
1. 不要濫用結構函數
結構函數雖然可以提高代碼的可讀性和可靠性,但也需要謹慎使用。濫用結構函數會造成代碼的複雜性,對程序性能產生影響。
2. 注意結構函數的訪問許可權
結構函數可以是公有、私有或受保護的,需要根據實際應用場景進行選擇。
3. 不允許自動轉換
結構函數不能有返回值類型,也不允許自動類型轉換,只能通過顯示類型轉換完成。
4. 繼承和多態
結構函數的繼承和多態是C++面向對象編程的重要特性,可以實現代碼的可擴展性和復用性。
六、總結
結構函數是一種特殊的成員函數,用於在創建對象時進行初始化操作。C++結構函數可分為默認結構函數、拷貝結構函數、移動結構函數和轉換結構函數等幾種類型。在使用結構函數時,需要注意虛擬結構函數、純虛擬結構函數的定義和繼承、多態等特性。通過合理的應用結構函數,可以提高代碼的可讀性和可靠性,增強程序的穩定性和可擴展性。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/243837.html