C++基礎--static靜態成員
1. 靜態區域性物件
靜態區域性物件是位於函式內的靜態變數,在呼叫函式前就被建立並賦初值,在程式結束前都不會被撤銷,在函式多次呼叫過程中持續存在並保持它的值。
在標頭檔案中定義靜態變數不可行。因為如果在使用該標頭檔案的每個C語言檔案中定義靜態變數,則每個標頭檔案中都會存在一個單獨的靜態變數,會引起空間浪費或程式錯誤。不推薦在標頭檔案中定義任何變數。
2. 靜態類成員
static成員與類關聯,獨立於類的任意物件,類的全體物件共享static成員。static成員遵循正常公有/私有訪問規則。如果基類定義了static成員。如果不是private,既可以通過基類訪問該成員,也可以通過派生類訪問;如果是private,派生類不能訪問。
例如,銀行賬戶類,每個使用者具有餘額和擁有者,但每個賬戶利率相同。利率可以作為靜態類成員,計算利率的函式為靜態成員函式。或者,統計已建立的特定類型別物件的數量。
2.1 宣告和定義
宣告:在成員宣告前加上關鍵字static,關鍵字只出現在宣告處。
定義:類外定義使用作用域操作符將類和成員關聯。一般類的成員不能在類的定義體中初始化。但只要初始化式為常量表達式,整型const static資料成員就可在類的定義體中初始化,但仍必須在類外再定義,只是不必再指定初始值。
2.2 static資料成員
static資料成員必須在類定義體外部定義且只定義一次,無需重複指定static保留字。不能通過建構函式初始化,應該在定義時初始化。一旦成員名出現,成員定義就在類的作用域中,可直接使用static成員函式初始化。
static資料成員的型別可以是該成員所屬的類型別,非static成員被限定為自身類物件的指標或引用。
static資料成員可用作預設實參,非static成員不能用作預設實參,因為它的值不能獨立於所屬物件而使用。
2.3 static成員函式
static成員函式不是任何物件的組成部分,所以它沒有this指標,不能被宣告為const(因為將成員函式宣告為const表示不會修改該函式所在物件),也不能被宣告為虛擬函式。可以直接訪問所屬類的static成員,但不能直接使用非static成員。
使用
- 通過作用域操作符”::”直接呼叫static成員
- 通過物件、引用、指標間接呼叫
類的static成員的優點:
- 成員名在類的作用域中,避免與其他類成員或全域性物件名字衝突
- 可以實施封裝。static成員可以是私有成員,全域性物件不可以,全域性物件會破壞封裝
- 與特定類關聯。清晰顯示程式設計師意圖
3. 全域性變數 VS 靜態變數
a) 相同:都保留在靜態儲存區,生命週期都為整個程式
b) 全域性變數作用域為整個程式,在一個原始檔中定義,可作用於所有原始檔,不包含全域性變數的原始檔使用extern關鍵字再次宣告。若區域性重新定義,作用域除了這個區域性。
靜態區域性變數只對定義自己的函式體可見,靜態全域性變數作用於定義它的檔案。
#include <iostream>
#include <string>
using namespace std;
class Account {
public:
void applyint(){
amount += amount * interestRate;
}
//靜態成員函式
static double rate(){ //返回利息
return interestRate;
}
static void rate(double); //設定新利息
private:
string owner;
double amount;
//只要初始化式為常量表達式,整型const static資料成員就可在類的定義體中初始化
static const int period = 30;
double daily_tbl[period];
static double interestRate;
static double initRate();
};
//Account的每個物件有兩個資料成員,沒有與static資料成員對應的資料成員,全體物件共享interestRate。
//static資料成員必須在類定義體外部定義且只定義一次。一旦成員名出現,成員定義就在類的作用域中,可直接使用static成員函式初始化
double Account::initRate() {
interestRate = 3.0;
}
double Account::interestRate = initRate();
//const int Account::period;
//類外部定義靜態成員函式時,無需重複static保留字
void Account::rate(double newRate){
interestRate = newRate;
}
int main(){
Account ac1;
Account *ac2 = &ac1;
double rate;
//正常呼叫靜態成員函式
rate = ac1.rate();
rate = ac2->rate();
//使用作用域操作符用類直接呼叫靜態成員函式
Account::rate();
return 0;
}