1、構造函數
1.1?什么是構造函數
? ? ? ? 類的構造函數是類的一種特殊的成員函數,它會在每次創建類的新對象時執行。
? ? ? ? 每次構造的是構造成員變量的初始化值,內存空間等。
? ? ? ? 構造函數的名稱與類的名稱是完全相同的,并且不會返回任何類型,也不會返回 void。構造函數可用于為某些成員變量設置初始值。
#include <iostream>
#include <string>using namespace std; // 使用std命名空間class Car {
public:string brand; // 不需要使用std::stringint year;// 無參構造函數Car() {brand = "未知";year = 0;cout << "無參構造函數被調用" << endl; // 不需要使用std::cout和std::endl}void display() {cout << "Brand: " << brand << ", Year: " << year << endl;}
};int main() {Car myCar; // 創建Car對象myCar.display(); // 顯示車輛信息return 0;
}
1.2?帶參數的構造函數
? ? ? ? 默認的構造函數沒有任何參數,但如果需要,構造函數也可以帶有參數。這樣在創建對象時就會給對象賦初始值。
#include <iostream>
#include <string>using namespace std;class Car {
public:string brand;int year;// 帶參數的構造函數,使用常規的賦值方式Car(string b, int y) {brand = b;year = y;}void display() {cout << "Brand: " << brand << ", Year: " << year << endl;}
};int main() {Car myCar("Toyota", 2020); // 使用帶參數的構造函數創建Car對象myCar.display(); // 顯示車輛信息return 0;
}
1.3?使用初始化列表
? ? ? ? 在C++中,使用初始化列表來初始化類的字段是一種高效的初始化方式,尤其在構造函數中。初始化列表直接在對象的構造過程中初始化成員變量,而不是先創建成員變量后再賦值。這對于提高性能尤其重要,特別是在涉及到復雜對象或引用和常量成員的情況下。
????????初始化列表緊跟在構造函數參數列表后面,以冒號( : )開始,后跟一個或多個初始化表達式,每個表達式通常用逗號分隔。下面是使用初始化列表初始化字段的例子:
class MyClass {
private:int a;double b;std::string c;public:// 使用初始化列表來初始化字段MyClass(int x, double y, const std::string& z) : a(x), b(y), c(z) {// 構造函數體}
};
? ? ? ? 在這個例子中, MyClass 有三個成員變量: a ( int 類型)、 b ( double 類型)和 c
? ? ? ? (1) 效率 :對于非基本類型的對象,使用初始化列表比在構造函數體內賦值更高效,因為它避免了先默 認構造然后再賦值的額外開銷;
????????使用初始化列表是C++中推薦的初始化類成員變量的方式,因為它提供了更好的性能和靈活性。
1.4?拷貝構造函數
1.4.1?基本概念及發生條件
//其中, other 是對同類型對象的引用,通常是常量引用。
class MyClass {
public:MyClass(const MyClass& other);
};
#include <iostream>
#include <string>using namespace std;class Car {
public:string brand;int year;// 常規構造函數Car(string b, int y) : brand(b), year(y) {}// 拷貝構造函數Car(const Car& other) {brand = other.brand;year = other.year;cout << "拷貝構造函數被調用" << endl;}void display() {cout << "Brand: " << brand << ", Year: " << year << endl;}
};int main() {Car car1("Toyota", 2020); // 使用常規構造函數Car car2 = car1; // 使用拷貝構造函數car1.display();car2.display();return 0;
}
1.4.2?淺拷貝
? ? ? ? 淺拷貝只復制對象的成員變量的值。如果成員變量是指針,則復制指針的值(即內存地址),而不是指針所指向的實際數據。這會導致多個對象共享相同的內存地址。
#include <iostream>using namespace std;class Shallow {
public:int* data;Shallow(int d) {//(d):這是初始化表達式。在這里,分配的 int 類型內存被初始化為 d 的值。如果 d 的值是20,那么分配的內存將被初始化為 20。data = new int(d); // 動態分配內存cout << "觀察數據:" << endl;cout << d << endl;cout << *data << endl;cout << "觀察內存在構造函數中:" << endl;cout << data << endl;}// 默認的拷貝構造函數是淺拷貝~Shallow() {delete data; // 釋放內存}
};int main() {Shallow obj1(20);Shallow obj2 = obj1; // 淺拷貝cout << "觀察內存在main函數obj2的data地址:" << endl;cout << obj2.data << endl;cout << "obj1 data: " << *obj1.data << ", obj2 data: " << *obj2.data << endl;return 0;
}
? ? ? ? 在這個例子中, obj2 是通過淺拷貝 obj1 創建的。這意味著 obj1.data 和 obj2.data 指向相同的內存地址。當 obj1 和 obj2 被銷毀時,同一內存地址會被嘗試釋放兩次,導致潛在的運行時錯誤。 在Linux中我們獲得如下運行結果:
1.4.3?深拷貝
? ? ? ? 深拷貝復制對象的成員變量的值以及指針所指向的實際數據。這意味著創建新的獨立副本,避免了共享內存地址的問題。
#include <iostream>using namespace std;class Deep {
public:int* data;Deep(int d) {data = new int(d); // 動態分配內存cout << "觀察數據:" << endl;cout << d << endl;cout << *data << endl;cout << "觀察內存在構造函數中:" << endl;cout << data << endl;}// 顯式定義深拷貝的拷貝構造函數Deep(const Deep& source) {data = new int(*source.data); // 復制數據,而不是地址cout << "深拷貝構造函數\n";}~Deep() {delete data; // 釋放內存}
};int main() {Deep obj1(20);Deep obj2 = obj1; // 深拷貝cout << "觀察內存在main函數obj2的data地址:" << endl;cout << obj2.data << endl;cout << "obj1 data: " << *obj1.data << ", obj2 data: " << *obj2.data << endl;return 0;
}
? ? ? ? 在這個例子中, obj2 是通過深拷貝 obj1 創建的。這意味著 obj1.data 和 obj2.data 指向不同的內存地址。每個對象有自己的內存副本,因此不會相互影響,避免了潛在的運行時錯誤。
1.4.4?規則三則
? ? ? ? ?在C++中,規則三則(Rule of Three)是一個面向對象編程原則,它涉及到類的拷貝控制。規則三則指出,如果你需要顯式地定義或重載類的任何一個拷貝控制操作(拷貝構造函數、拷貝賦值運算符、析構函數),那么你幾乎肯定需要顯式地定義或重載所有三個。這是因為這三個功能通常都是用于管理動態分配的資源,比如在堆上分配的內存。
#include <iostream>
#include <cstring>class MyClass {
private:char* buffer;public:// 構造函數MyClass(const char* str) {if (str) {buffer = new char[strlen(str) + 1];strcpy(buffer, str);} else {buffer = nullptr;}}// 析構函數~MyClass() {delete[] buffer;}// 拷貝構造函數MyClass(const MyClass& other) {if (other.buffer) {buffer = new char[strlen(other.buffer) + 1];strcpy(buffer, other.buffer);} else {buffer = nullptr;}}// 拷貝賦值運算符MyClass& operator=(const MyClass& other) {if (this != &other) {delete[] buffer; // 首先刪除當前對象的資源if (other.buffer) {buffer = new char[strlen(other.buffer) + 1];strcpy(buffer, other.buffer);} else {buffer = nullptr;}}return *this;}
};int main() {MyClass obj1("Hello");MyClass obj2 = obj1; // 調用拷貝構造函數MyClass obj3("World");obj3 = obj1; // 調用拷貝賦值運算符return 0;
}
? ? ? ? 在這個例子中,構造函數為成員變量 buffer 分配內存,并復制給定的字符串;析構函數釋放 buffer 所占用的內存,以避免內存泄露;拷貝構造函數創建一個新對象作為另一個現有對象的副本,并為其分配新的內存,以避免多個對象共享同一內存;拷貝賦值運算符更新對象時,首先釋放原有資源,然后根據新對象的狀態分配新資源。
????????這個類遵循規則三則,確保了動態分配資源的正確管理,避免了內存泄露和淺拷貝問題。
1.4.5?避免不必要的拷貝
? ? ? ? 避免不必要的拷貝是 C++ 程序設計中的一個重要原則,尤其是在處理大型對象或資源密集型對象時。使用引用(包括常量引用)和移動語義(C++11 引入)是實現這一目標的兩種常見方法。
1.4.5.1 使用引用傳遞對象
? ? ? ? 通過使用引用(尤其是常量引用)來傳遞對象,可以避免在函數調用時創建對象的副本。
#include <iostream>
#include <vector>using namespace std;class LargeObject {// 假設這是一個占用大量內存的大型對象
};void processLargeObject(const LargeObject& obj) {// 處理對象,但不修改它cout << "Processing object..." << endl;
}int main() {LargeObject myLargeObject;processLargeObject(myLargeObject); // 通過引用傳遞,避免拷貝return 0;
}
? ? ? ? 在這個例子中, processLargeObject 函數接受一個對 LargeObject 類型的常量引用,避免了在函數調用時復制整個 LargeObject 。
1.4.5.2?使用移動語義
? ? ? ? C++11 引入了移動語義,允許資源(如動態分配的內存)的所有權從一個對象轉移到另一個對象,這避免了不必要的拷貝。
#include <iostream>
#include <utility> // 對于 std::moveusing namespace std;class MovableObject {
public:MovableObject() {// 構造函數}MovableObject(const MovableObject& other) {// 拷貝構造函數(可能很昂貴)}MovableObject(MovableObject&& other) noexcept {// 移動構造函數(輕量級)// 轉移資源的所有權}MovableObject& operator=(MovableObject&& other) noexcept {// 移動賦值運算符// 轉移資源的所有權return *this;}
};MovableObject createObject() {MovableObject obj;return obj; // 返回時使用移動語義,而非拷貝
}int main() {MovableObject obj = createObject(); // 使用移動構造函數return 0;
}
? ? ? ? 在這個例子中, MovableObject 類有一個移動構造函數和一個移動賦值運算符,它們允許對象的資源(如動態分配的內存)在賦值或返回時被“移動”而非復制。這減少了對資源的不必要拷貝,提高了效率。通過這些方法,可以在 C++ 程序中有效地減少不必要的對象拷貝,尤其是對于大型或資源密集型的對象。
1.4.6 拷貝構造函數的隱式調用
? ? ? ? 在C++ 中,拷貝構造函數可能會在幾種不明顯的情況下被隱式調用。這種隱式調用通常發生在對象需要被復制時,但代碼中并沒有明顯的賦值或構造函數調用。了解這些情況對于高效和正確地管理資源非常重要。
1.4.6.1?作為函數參數傳遞(按值傳遞)
? ? ? ? 當對象作為函數參數按值傳遞時,會調用拷貝構造函數來創建參數的本地副本。
#include <iostream>using namespace std;class MyClass {
public:MyClass() {}MyClass(const MyClass &) {cout << "拷貝構造函數被隱式調用" << endl;}
};void function(MyClass obj) {// 對 obj 的操作
}int main() {MyClass myObject;function(myObject); // 調用 function 時,拷貝構造函數被隱式調用return 0;
}
1.4.6.2?從函數返回對象(按值返回)
? ? ? ? 當函數返回一個對象時,拷貝構造函數會被用于創建返回值的副本。
MyClass function() {MyClass tempObject;return tempObject; // 返回時,拷貝構造函數被隱式調用
}int main() {MyClass myObject = function(); // 接收返回值時可能還會有一次拷貝(或移動)return 0;
}
1.4.6.3?初始化另一個對象
? ? ? ? 當用一個對象初始化另一個同類型的新對象時,會使用拷貝構造函數。
int main() {MyClass obj1;MyClass obj2 = obj1; // 初始化時,拷貝構造函數被隱式調用return 0;
}
? ? ? ? 在所有這些情況下,如果類包含資源管理(例如,動態內存分配),那么正確地實現拷貝構造函數是非常重要的,以確保資源的正確復制和管理,防止潛在的內存泄漏或其他問題。此外,隨著 C++11 的引入,移動語義提供了對資源的高效管理方式,可以減少這些場景中的資源復制。
1.4.7?禁用拷貝構造函數
? ? ? ? 在C++ 中,禁用拷貝構造函數是一種常用的做法,尤其是在設計那些不應該被復制的類時。這可以通過將拷貝構造函數聲明為 private 或使用 C++11 引入的 delete 關鍵字來實現。這樣做的目的是防止類的對象被拷貝,從而避免可能導致的問題,如資源重復釋放、無意義的資源復制等。
1.4.7.1?使用?delete?關鍵字
? ? ? ? 在 C++11 及更高版本中,可以使用 delete 關鍵字明確指定不允許拷貝構造,這種方法清晰明了,它向編譯器和其他程序員直接表明該類的對象不能被拷貝。
class NonCopyable {
public:NonCopyable() = default; // 使用默認構造函數// 禁用拷貝構造函數NonCopyable(const NonCopyable&) = delete;// 禁用拷貝賦值運算符NonCopyable& operator=(const NonCopyable&) = delete;
};int main() {NonCopyable obj1;// NonCopyable obj2 = obj1; // 編譯錯誤,拷貝構造函數被禁用return 0;
}
1.4.7.2?使用 private 聲明(C++98/03)
? ? ? ? 在C++11 之前,常見的做法是將拷貝構造函數和拷貝賦值運算符聲明為 private ,并且不提供實現:
class NonCopyable {
private:// 將拷貝構造函數和拷貝賦值運算符設為私有NonCopyable(const NonCopyable&);NonCopyable& operator=(const NonCopyable&);public:NonCopyable() {}
};int main() {NonCopyable obj1;// NonCopyable obj2 = obj1; // 編譯錯誤,因為無法訪問私有的拷貝構造函數return 0;
}
? ? ? ? ?在這個例子中,任何嘗試拷貝 NonCopyable 類型對象的操作都會導致編譯錯誤,因為拷貝構造函數和拷貝賦值運算符是私有的,外部代碼無法訪問它們。
????????通過這些方法,可以確保類的對象不會被意外地拷貝,從而避免可能出現的資源管理相關的錯誤。
1.4.8?小結
? ? ? ? 在C++ 中拷貝構造函數需要注意的要點:
?要點 | 描述 |
定義和作用 | 拷貝構造函數在創建對象作為另一個現有對象副本時調用, 通常有一個對同 類型對象的常量引用參數。 |
語法 | 典型聲明為 ClassName(const ClassName &other) 。 |
深拷貝與淺拷貝 | 淺拷貝復制值,深拷貝創建資源的獨立副本。對于包含指針的類,深拷貝通常必要。 |
規則三則 (Rule of Three) | 如果實現了拷貝構造函數、拷貝賦值運算符或析構函數中的任何一個,通常應該實現所有三個。 |
避免不必要的拷貝 | 對于大型對象,使用移動語義避免不必要的拷貝,并在傳遞對象時使用引用或指針。 |
拷貝構造函數的隱 式調用 | 不僅在顯式復制時調用,也可能在將對象作為函數參數傳遞、從函數返回對象時隱式調用。 |
禁用拷貝構造函數 | 對于某些類,可以通過將拷貝構造函數聲明為私有或使用 delete 關鍵字 禁用拷貝。 |
1.5?this?關鍵字
? ? ? ? 在C++ 中, this 關鍵字是一個指向調用對象的指針。它在成員函數內部使用,用于引用調用該函數的對象。使用 this 可以明確指出成員函數正在操作的是哪個對象的數據成員。下面是一個使用 Car 類來展示 this 關鍵字用法的示例:
#include <iostream>
#include <string>using namespace std;class Car {
private:string brand;int year;public:Car(string brand, int year) {this->brand = brand;this->year = year;// cout << "構造函數中:" << endl;// cout << this << endl;}void display() const {cout << "Brand: " << this->brand << ", Year: " << this->year << endl;// 也可以不使用 this->,直接寫 brand 和 year}Car& setYear(int year) {this->year = year; // 更新年份return *this; // 返回調用對象的引用}
};int main()
{Car car("寶馬",2024);car.display();// 鏈式調用car.setYear(2023).display();// cout << "main函數中:" << endl;// cout << &car << endl;// Car car2("寶馬",2024);// cout << "main函數中:" << endl;// cout << &car2 << endl;return 0;
}
? ? ? ? 在這個例子中, Car 類的構造函數使用 this 指針來區分成員變量和構造函數參數。同樣, setYear成員函數使用 this 指針來返回調用該函數的對象的引用,這允許鏈式調用,如myCar.setYear(2021).display(); 。在 main 函數中創建了 Car 類型的對象,并展示了如何使用這些成員函數。
1.6?new/delete?關鍵字
? ? ? ? 在C++中, new 關鍵字用于動態分配內存。它是C++中處理動態內存分配的主要工具之一,允許在程序運行時根據需要分配內存。
? ? ? ? 基本用法:
? ? ? ? (1)分配單個對象:使用 new 可以在堆上動態分配一個對象。例如, new int 會分配一個 int 類型的空間,并返回一個指向該空間的指針。
int* ptr = new int; //C語言中,int *p = (int *)malloc(sizeof(int));
? ? ? ? (2)分配對象數組: new 也可以用來分配一個對象數組。例如, new int[10] 會分配一個包含10個整數的 數組。
int* arr = new int[10]; //C語言中,int *arr = (int *)malloc(sizeof(int)*10);
? ? ? ? (3)初始化:可以在 new 表達式中使用初始化。對于單個對象,可以使用構造函數的參數。
MyClass* obj = new MyClass(arg1, arg2);
? ? ? ? 在使用 new 分配的內存必須顯式地通過 delete (對于單個對象)或 delete[] (對于數組)來釋放,以避免內存泄露:
? ? ? ? (1)釋放單個對象:
delete ptr; // 釋放 ptr 指向的對象
? ? ? ? (2)釋放數組:
delete[] arr; // 釋放 arr 指向的數組
? ? ? ? 注:(1)異常安全:如果 new 分配內存失敗,它會拋出 std::bad_alloc 異常(除非使用了 nothrow 版本);
? ? ? ? (2)內存泄露:忘記釋放使用 new 分配的內存會導致內存泄露;
? ? ? ? (3)匹配使用 delete 和 delete[] :為避免未定義行為,使用 new 分配的單個對象應該使用delete 釋放,使用 new[] 分配的數組應該使用 delete[] 釋放。
class MyClass {
public:MyClass() {std::cout << "Object created" << std::endl;}
};int main() {// 分配單個對象MyClass* myObject = new MyClass();// 分配對象數組int* myArray = new int[5]{1, 2, 3, 4, 5};// 使用對象和數組...// 釋放內存delete myObject;delete[] myArray;return 0;
}
? ? ? ? 在這個例子中, new 被用來分配一個 MyClass 類型的對象和一個整數數組,然后使用 delete 和delete[] 來釋放內存。每個 new 都對應一個 delete ,保證了動態分配的內存被適當管理。
2、析構函數
? ? ? ? 析構函數是C++中的一個特殊的成員函數,它在對象生命周期結束時被自動調用,用于執行對象銷毀前的清理工作。析構函數特別重要,尤其是在涉及動態分配的資源(如內存、文件句柄、網絡連接等)的情況下。
? ? ? ? 基本特性:
? ? ? ? (1)名稱:析構函數的名稱由波浪號( ~ )后跟類名構成,如 ~MyClass() 。
? ? ? ? (2)無返回值和參數:析構函數不接受任何參數,也不返回任何值。
? ? ? ? (3)自動調用:當對象的生命周期結束時(例如,一個局部對象的作用域結束,或者使用 delete 刪除一個動態分配的對象),析構函數會被自動調用。
? ? ? ? (4)不可重載:每個類只能有一個析構函數。
? ? ? ? (5)繼承和多態:如果一個類是多態基類,其析構函數應該是虛的。
#include <iostream>using namespace std;class MyClass{
private:int* datas;public:MyClass(int size){datas = new int[size];}~MyClass(){cout << "析構函數被調用" << endl;delete[] datas;}
};int main()
{MyClass m1(5);MyClass *m2 = new MyClass(10);delete m2;return 0;
}
? ? ? ? ?在這個示例中, MyClass 的構造函數分配了一塊內存,而析構函數釋放了這塊內存。當 obj 的生命周期結束時(即離開了它的作用域), MyClass 的析構函數被自動調用,負責清理資源,防止內存泄露。
? ? ? ? 析構函數在管理資源方面非常重要。沒有正確實現析構函數,可能導致資源泄露或其他問題。在基于RAII(資源獲取即初始化)原則的C++編程實踐中,確保資源在對象析構時被適當釋放是非常關鍵的。當使用智能指針和其他自動資源管理技術時,可以減少顯式編寫析構函數的需要,但了解析構函數的工作原理仍然很重要。
? ? ? ? 關于析構函數的要點:
要點 | 描述 |
定義和作 用 | 析構函數在對象生命周期結束時自動調用,用于清理對象可能持有的資源。 |
語法 | 析構函數名稱由波浪線 (~) 后跟類名構成,例如 MyClass 的析構函數為~MyClass() 。 |
資源管理 | 用于釋放對象在生命周期中分配的資源,如動態內存、文件句柄、網絡連接等。 |
自動調用機制 | 當對象離開其作用域或通過 delete 刪除時,將自動調用其析構函數。 |
防止資源 泄露 | 正確實現析構函數對防止資源泄露至關重要,特別是在涉及動態資源分配的情況。 |
虛析構函數 | 如果類作為基類設計,應有一個虛析構函數,以確保正確調用派生類的析構函數。 |
析構函數與異常 | 析構函數不應拋出異常,如果可能拋出,應在函數內捕獲。 |
刪除的析構函數 | 可以通過將析構函數聲明為刪除( ~MyClass() = delete; )來禁止刪除某類對象。 |
與構造函 數的關系 | 每個類只能有一個析構函數,不可重載,與構造函數相比。 |
規則三則/ 五則 | 如果類需要自定義析構函數、拷貝構造函數或拷貝賦值運算符,可能也需要自定義另外兩個(規則三則)。在 C++11 后還包括移動構造函數和移動賦值運算符(規則五則)。 |
3、靜態成員
3.1?靜態成員的定義
? ? ? ? 靜態成員在C++類中是一個重要的概念,它包括靜態成員變量和靜態成員函數。靜態成員的特點和存在的意義如下:
? ? ? ? 靜態成員變量:
? ? ? ? (1)定義:靜態成員變量是類的所有對象共享的變量。與普通成員變量相比,無論創建了多少個類的實例,靜態成員變量只有一份拷貝。
? ? ? ? (2)初始化:靜態成員變量需要在類外進行初始化,通常在類的實現文件中。
? ? ? ? (3)訪問:靜態成員變量可以通過類名直接訪問,不需要創建類的對象。也可以通過類的對象訪問。
? ? ? ? (4)用途:常用于存儲類級別的信息(例如,計數類的實例數量)或全局數據需要被類的所有實例共享。
? ? ? ? 靜態成員函數:
? ? ? ? (1)定義:靜態成員函數是可以不依賴于類的實例而被調用的函數。它不能訪問類的非靜態成員變量和非靜態成員函數。
? ? ? ? (2)訪問:類似于靜態成員變量,靜態成員函數可以通過類名直接調用,也可以通過類的實例調用。
? ? ? ? (3)用途:常用于實現與具體對象無關的功能,或訪問靜態成員變量。
class MyClass {
public:static int staticValue; // 靜態成員變量MyClass() {// 每創建一個對象,靜態變量增加1staticValue++;}static int getStaticValue() {// 靜態成員函數return staticValue;}
};// 類外初始化靜態成員變量
int MyClass::staticValue = 0;int main() {MyClass obj1, obj2;std::cout << MyClass::getStaticValue(); // 輸出2
}
? ? ? ? 靜態成員的優點:
? ? ? ? (1)共享數據:允許對象之間共享數據,而不需要每個對象都有一份拷貝。
? ? ? ? (2)節省內存:對于頻繁使用的類,使用靜態成員可以節省內存。
? ? ? ? (3)獨立于對象的功能:靜態成員函數提供了一種在不創建對象的情況下執行操作的方法,這對于實現工具函數或管理類級別狀態很有用。
3.2?靜態成員變量的作用
? ? ? ? 靜態成員變量在C++中的一個典型應用是用于跟蹤類的實例數量。這個案例體現了靜態成員變量的特性:它們在類的所有實例之間共享,因此適合于存儲所有實例共有的信息。
#include <iostream>using namespace std;class Myclass{
private:static int staticNumofInstance;public:Myclass(){staticNumofInstance++;}~Myclass(){staticNumofInstance--;}static int getNunofInstance(){return staticNumofInstance;}
};int Myclass::staticNumofInstance = 0;int main()
{Myclass m1;cout << Myclass::getNunofInstance() << endl;Myclass m2;cout << m2.getNunofInstance() << endl;{Myclass m3;cout << Myclass::getNunofInstance() << endl;Myclass m4;cout << Myclass::getNunofInstance() << endl;}cout << Myclass::getNunofInstance() << endl;Myclass *m5 = new Myclass;cout << Myclass::getNunofInstance() << endl;delete m5;cout << Myclass::getNunofInstance() << endl;return 0;
}
? ? ? ? 在這個例子中: Myclass 類有一個靜態成員變量 staticNumofInstance ,用來跟蹤該類的實例數量。每當創建 Myclass 的新實例時,構造函數會增加 staticNumofInstance 。每當一個 Myclass 實例被銷毀時,析構函數會減少 staticNumofInstance 。通過靜態成員函數 getNunofInstance 可以隨時獲取當前的實例數量。靜態成員變量 staticNumofInstance 在類外初始化為0。
????????這個案例展示了靜態成員變量如何在類的所有實例之間共享,并為所有實例提供了一個共同的狀態(在這個例子中是實例的數量)。這種技術在需要跟蹤對象數量或實現某種形式的資源管理時特別有用。