在這個學習過程中我對 static 及 const 的使用時常會混淆,因此整理,加深記憶
一、類的靜態成員
如果某個屬性為整個類所共有,不屬於任何一個具體對象,則采用 static 關鍵字來聲明靜態成員。
• 由於靜態數據成員不屬於任何一個對象,因此可以通過類名對它進行訪問。
使用方法----- "類名::標識符“ (注意:static 數據成員的初始化要在類定義之外在加以定義)
1.靜態數據成員
#include<iostream> using namespace std; class Dog { public: Dog(int age, int weight); void show(); ~Dog() {} private: static int number; int age, weight; }; int Dog::number = 0; //static 數據的定義【因為需要這種方式專門為它們分配空間,而非靜態數據是與它們的所屬對象一同分配空間的】 Dog::Dog(int age, int weight) { //構造函數 this->age = age; this->weight = weight; number++; } void Dog::show() { cout << "age: " << age << "歲 " << "weight: " << weight <<"kg"<< endl; cout << "現在共有" << number << "只汪星人" << endl; } int main() { Dog dog(1, 20); dog.show(); Dog dog2(2, 30); dog2.show(); return 0; }
結果如下:
不難發現當調用構造函數時 計算汪星人的數量的 number靜態數據 做自增運算時,無論在哪個對象里number的值隨上一次調用而繼續加一。
有個細節:static 數據類型 在定義時不給它設定值的化,系統默認為 0,而非靜態數據類型則隨機賦值。(ps:下面代碼 14 行也值得注意)
1 #include<iostream> 2 using namespace std; 3 4 class Point { 5 public: 6 Point() {}; 7 void set(int x, int y); 8 int getx() { return x; } 9 int gety() { return y; } 10 private: 11 int x; 12 static int y; 13 }; 14 int Point::y; //切記,哪怕不給static類型 定義時賦初值,也需要在類外面定義【即分配空間】,否則會報錯 15 void Point::set(int x, int y) { 16 this->x = x; 17 this->y = y; 18 } 19 int main() { 20 Point p; 21 cout << p.getx() << " " << p.gety() << endl; 22 return 0; 23 }
結果如下:
2.靜態成員函數
靜態成員函數可以直接訪問該類的數據和函數成員,而訪問非靜態成員必須通過對象名
class A { public: static void f(A a); private: int x; static int y; }; static int y; void A::f(A a) { cout << x; //錯誤 cout << a.x; //正確 cout << y; //直接訪問static 數據正確 }
從上面幾個例子中,我們發現靜態成員函數可以直接訪問靜態數據類型而訪問非靜態數據類型時需要通過對象名來實現。
而非靜態函數則可以直接訪問這兩種數據類型
靜態函數的訪問【例子】(注意22行):
1 #include <iostream> 2 3 using namespace std; 4 5 class Cat { 6 public: 7 Cat() { numOfCats++; } 8 9 static void getNumOfCats(); 10 11 private: 12 static int numOfCats; 13 }; 14 15 int Cat::numOfCats = 0; 16 17 void Cat::getNumOfCats() { 18 cout << "貓的數量:" << numOfCats << endl; 19 } 20 21 int main() { 22 Cat::getNumOfCats(); //static函數屬於類,並不屬於某個對象,所以可以這樣調用,當然通過對象也可以調用 23 Cat cat; 24 cat.getNumOfCats(); 25 Cat cat2; 26 cat.getNumOfCats(); 27 }
二. 常對象
常對象是這樣的對象:它的數據成員值在對下崗的整個生存周期內不能被改變,也就是說,常對象必須進行初始化而且不能被更新!
語法形式: const 類型說明符 對象名;
int main() { const int n = 10; //正確,用10對常對象初始化 n = 10; //錯誤,常對象不能被賦值 }
用const 修飾的類成員
1. 常成員函數
類型說明符 函數命(參數表) const ;
注意:
(1)const 是函數類型的組成成分,因此在函數定義部分也要帶const
(2)一個對象是常對象 ,則只能通過該常對象調用它的 常成員函數
(3)const關鍵字可以用於重載
1 #include<iostream> 2 using namespace std; 3 4 class R { 5 public: 6 R(int r1, int r2) :r1(r1), r2(r2) {} 7 void print(); 8 void print() const; //函數重載 9 private: 10 int r1, r2; 11 }; 12 13 void R::print() { 14 cout << r1 << " " << r2 << endl; 15 } 16 17 void R::print()const { //定義時const 依舊是要帶的 18 cout << r1 << " " << r2 << endl; 19 } 20 21 int main() { 22 R a(5, 4); 23 a.print(); //調用13行print函數
24 const R b(20, 52); 25 b.print(); //調用17行print函數
26 return 0; 27 }
結果如下:
在逐步調試的過程中發現 常對象 b 在調用print函數時,調用了常成員函數,而非const對象a調用了 非常成員函數
因為通過非const對象調用print函數,兩個重載函數都可以匹配,編譯器將選擇最近的函數重載----不帶const的函數
ps:如果該程序中只有帶const的print函數 則 普通對象a也是調用有const的print函數
But ,常對象b不能調用 普通print函數,因為普通print函數有着改值的可能,但常對象b不能改變值
2.常數據成員
將上面的代碼類的聲明改為
class R { public: R(int r1, int r2) :r1(r1), r2(r2) {} void print(); void print() const; private: const int r1, r2; //改為常數據 };
則類的初始化必須用
類名::類名(形參表):常數據1(形參1),常數據2(形參2)....{ }
因為常數據不能賦值!
還有一點,類的靜態常量如果具有整數類型或枚舉類型,那么直接可以在類定義中給它指定常量
class Dog { public: Dog() {} private: static const int a = 0; }; //=========上下二者等價================= class Dog { public: Dog(){} private: static const int a; }; int Dog::a = 0;
總結:
對比static 以及 const 的用法
1. static 類型數據可以通過 static類型或者 非static類型函數訪問並可以改變;
const類型數據不能改變;
2. static 函數可以直接訪問 類中 static 類型數據,但訪問非static數據需通過對象訪問;
const類型函數可以被調用於非const對象,但在對象是const類型時,通過該對象只能調用const類型函數
=============================================================================================
以上為現階段的學習記錄,如有錯誤希望指正 :)