學習C++ -> 類的特殊數據成員
在構造函數一節的介紹中, 我們已經提到了在C++中有幾類特殊的數據成員不能使用構造函數進行初始化, 他們有自己的初始化方式, 下面就具體介紹下這幾種數據成員。
一、const 數據成員
const 類型的數據成員具有只讀屬性, 在構造函數內進行初始化是不允許的, 例如以下代碼:
1 #include <iostream> 2 3 using namespace std; 4 5 class A 6 { 7 public: 8 A(int n = 0) { num = n; } //在構造函數內使用 n 初始化const型數據成員 num 9 void showNum() { cout<<"num = "<<num<<endl; } 10 private: 11 const int num; //const 型數據成員 12 }; 13 14 int main() 15 { 16 A a(10); 17 a.showNum(); 18 19 return 0; 20 }
嘗試編譯運行時報錯:
error: uninitialized member 'A::num' with 'const' type 'const int' error: assignment of read-only data-member 'A::num'
要初始化 const 型的數據成員, 必須通過初始化表達式來進行初始化, 一經初始化, 其值確定, 不能再被修改, 通過初始化表達式形式如下:
1 #include <iostream> 2 3 using namespace std; 4 5 class A 6 { 7 public: 8 A(int n = 0):num(n) { } //使用初始化表達式對const型數據成員進行初始化 9 void showNum() { cout<<"num = "<<num<<endl; } 10 private: 11 const int num; 12 }; 13 14 int main() 15 { 16 A a(10); 17 a.showNum(); 18 19 return 0; 20 }
二、引用類型的成員
對於引用類型的成員, 同樣只能通過初始化表達式進行初始化, 錯誤的示例這里不再舉出, 一個通過初始化表對引用類型初始化的示例:
1 #include <iostream> 2 3 using namespace std; 4 5 class A 6 { 7 public: 8 A(int &rn):rNum(rn) { } //使用初始化表達式對引用型數據成員進行初始化 9 void showNum() { cout<<"num = "<<rNum<<endl; } 10 private: 11 int &rNum; //引用類型 12 }; 13 14 int main() 15 { 16 int x = 10, &rx = x; 17 A a(rx); //傳遞引用類型 18 a.showNum(); 19 20 return 0; 21 }
三、類對象成員
類的對象可以作為另一個類的數據成員, 在定義類時, 與普通的數據成員一樣, 在聲明時無法進行初始化, 例如有個Line類中有兩個 Point 類的對象作為數據成員, 在聲明時
private: int xPos(10, 20); int yPos(100, 200);
這樣是錯誤的, 所以在初始化類對象成員時也需要一定的方法。
情況一:
還以 Line 類和 Point 類為例, 當 Point 類中的數據成員全部為 public 時, 可以在 Line 類的構造函數內完成初始化, 像以下示例的情況:
1 #include <iostream> 2 3 using namespace std; 4 5 class Point 6 { 7 public: 8 void printPoint() { cout<<"("<<xPos<<", "<<yPos<<")\n"; } 9 int xPos; //public類型的 xPos 和 yPos 10 int yPos; 11 }; 12 13 class Line 14 { 15 public: 16 Line(int x1, int y1, int x2, int y2) 17 { 18 M.xPos = x1; M.yPos = y1; //在構造函數內完成類對象的初始化 19 N.xPos = x2; N.yPos = y2; 20 } 21 void printLine() { M.printPoint(); N.printPoint(); } 22 private: 23 Point M; //類對象成員, M和N 24 Point N; 25 }; 26 27 int main() 28 { 29 Line L(10, 20, 100, 200); 30 L.printLine(); 31 32 return 0; 33 }
編譯運行的結果:
(10, 20) (100, 200) Process returned 0 (0x0) execution time : 0.500 s Press any key to continue.
代碼說明:
由於 Point 類中的數據成員全為 public 的, 所以可以通過 對象名.數據成員名 的方式直接進行訪問。 可以看到, Line 類中有兩個 Point 類型的數據成員, M和N, 然后通過 對象名.數據成員名 的方式在 Line 類的構造函數中完成初始化。
情況二:
由於類的數據成員一般都為 private 型的, 再使用上面的方式進行初始化就不適合了, 因為 private 數據是不允許外部直接訪問的, 將 Point 類中的數據成員改為 private 后再編譯運行代碼便會報出 error: 'int Point::xPos' is private 這樣的錯誤。
要在 Line 類中對 Point 的 private 數據成員進行正常的初始化同樣需要借助初始化表達式來完成, 修改后的示例:
1 #include <iostream> 2 3 using namespace std; 4 5 class Point 6 { 7 public: 8 Point(int x, int y) { xPos = x; yPos = y; } 9 void printPoint() { cout<<"("<<xPos<<", "<<yPos<<")\n"; } 10 private: 11 int xPos; //private類型的 xPos 和 yPos 12 int yPos; 13 }; 14 15 class Line 16 { 17 public: 18 Line(int x1, int y1, int x2, int y2):M(10, 20), N(100, 200) { ; } //借助初始化表達式完成對M,N的初始化 19 void printLine() { M.printPoint(); N.printPoint(); } 20 private: 21 Point M; //類對象成員, M和N 22 Point N; 23 }; 24 25 int main() 26 { 27 Line L(10, 20, 100, 200); 28 L.printLine(); 29 30 return 0; 31 }
運行輸出后的結果與上例中是相同的。
代碼說明:
通過初始化表達式對象 L 中的 M、N 數據成員的初始化順序如下: 首先 M 對象的構造函數被調用, 接着調用 N 對象的構造函數, 最后 Line 類的構造函數被調用, 這樣便完成了類對象成員的初始化。
四、static類型數據成員
static 類型的數據成員為靜態成員, 他的特點是: 無論對象創建了多少個, 該數據成員的實例只有一個, 會被該類所創建的所有對象共享, 其中任何一個對象對其操作都會影響到其他對象。該類型的數據初始化是放在類外進行的, 其基本格式如下:
類型 類名::成員變量名 = 初始化值/表達式;
一個示例: 統計一共創建了多少個對象, 並且在一番銷毀后還剩多少。
1 #include <iostream> 2 3 using namespace std; 4 5 class Book 6 { 7 public: 8 Book() { ibookNumber++; } //通過構造函數訪問static型數據ibookNumber並使其自增1 9 ~Book() { ibookNumber--; } //對象在被撤銷時將static型數據ibookNumber並使其自減1 10 void showNum() { cout<<"Book number = "<<ibookNumber<<endl; } 11 private: 12 static int ibookNumber; //static類型數據成員 ibookNumber 13 }; 14 15 int Book::ibookNumber = 0; //在類外對static類型的數據成員進行初始化 16 17 int main() 18 { 19 Book A; Book B; Book C; Book D; Book E; //創建一些對象 20 A.showNum(); //使用對象A查看當前對象個數 21 B.showNum(); //使用對象B查看當前對象個數 22 cout<<"銷毀一些對象...\n"; 23 B.~Book(); C.~Book(); //將B、C對象進行撤銷 24 D.showNum(); //使用D對象查看剩余對象個數 25 E.showNum(); //使用E對象查看剩余對象個數 26 27 return 0; 28 }
編譯運行的結果:
Book number = 5 Book number = 5 銷毀一些對象... Book number = 3 Book number = 3 Process returned 0 (0x0) execution time : 0.266 s Press any key to continue.
代碼說明:
在上面代碼的類Book中, 我們聲明了一個 static 類型的 ibookNumber 作為創建多少對象的統計變量, Book的構造函數的作用是當對象創建時將 ibookNumber 的值自增1, 而析構函數的則負責將 ibookNumber 自減1。
main函數中, 創建了 A-E共5個對象, 在創建完成后, 通過 A 對象輸出對象的總數和 B 對象輸出的結果是相同的, 都是5個, 然后銷毀 B、C 對象, 用D、E對象查看剩余對象個數, 結果都為3, 可以看出, static型的數據成員任何對象都可以進行訪問, 並且在創建后所產生的實例是唯一的。
--------------------
wid, 2013.02.23
上一篇: 學習C++ -> 復制構造函數