C++ static 的六個隱藏技能,90% 程序員都被這些小心機(jī)驚到了!
今天咱們來聊聊 C++ 里那個看似簡單,實(shí)則"心機(jī)滿滿"的關(guān)鍵字——static。
說起static,可能很多小伙伴會想:"不就是個靜態(tài)變量嗎,有啥好說的?"
嘿嘿,如果你真這么想,那今天這篇文章你可得好好看看了。static這家伙在C++里可是個"多面手",它的用法多到能讓你懷疑人生!
別急,今天我就用最通俗易懂的方式,帶你把 static 的各種"小心機(jī)"都搞清楚。保證看完之后,你再也不會被 static 給繞糊涂了!
第一招:局部靜態(tài)變量 —— 函數(shù)里的"釘子戶"
咱們先從最常見的說起。你有沒有想過,普通的局部變量每次函數(shù)調(diào)用完就"死翹翹"了,但有時候我們希望它能"活"得久一點(diǎn),記住上次的值?
這時候static就派上用場了!
#include <iostream>
using namespace std;
void countCalls() {
static int count = 0; // 這家伙是個"釘子戶"
count++;
cout << "函數(shù)被調(diào)用了第 " << count << " 次" << endl;
}
int main() {
countCalls(); // 輸出:函數(shù)被調(diào)用了第 1 次
countCalls(); // 輸出:函數(shù)被調(diào)用了第 2 次
countCalls(); // 輸出:函數(shù)被調(diào)用了第 3 次
return 0;
}
看見沒?這個count變量就像個"釘子戶",賴在內(nèi)存里不走了!每次函數(shù)調(diào)用完,它都還記得自己的值。
重點(diǎn)來了: static局部變量只在第一次進(jìn)入函數(shù)時初始化,之后就一直"賴著不走"。
第二招:全局靜態(tài)變量 —— 文件里的"獨(dú)行俠"
如果說普通的全局變量是"社交達(dá)人",哪個文件都能訪問它,那static全局變量就是個"獨(dú)行俠",只在自己的文件里混。
// file1.cpp
#include <iostream>
using namespace std;
static int secretNumber = 42; // 這是我的小秘密,別的文件別想碰!
void showSecret() {
cout << "我的秘密數(shù)字是:" << secretNumber << endl;
}
// 如果在file2.cpp里試圖訪問secretNumber,編譯器會告訴你:門都沒有!
這招特別適合寫一些"內(nèi)部專用"的全局變量,不想被其他文件"串門"的時候用。
第三招:靜態(tài)成員變量 —— 類的"公共財產(chǎn)"
這個就更有意思了!普通的成員變量每個對象都有一份,但static成員變量整個類就共享一份,就像是所有對象的"公共財產(chǎn)"。
#include <iostream>
using namespace std;
class Student {
public:
string name;
static int totalCount; // 所有學(xué)生的公共計數(shù)器
Student(string n) : name(n) {
totalCount++; // 每創(chuàng)建一個學(xué)生,計數(shù)器就+1
}
static void showTotal() {
cout << "目前總共有 " << totalCount << " 個學(xué)生" << endl;
}
};
// 重要:靜態(tài)成員變量需要在類外初始化!
int Student::totalCount = 0;
int main() {
Student s1("小明");
Student s2("小紅");
Student::showTotal(); // 輸出:目前總共有 2 個學(xué)生
Student s3("小剛");
Student::showTotal(); // 輸出:目前總共有 3 個學(xué)生
return 0;
}
看見沒?不管創(chuàng)建多少個Student對象,totalCount都只有一份,大家共享著用。
第四招:靜態(tài)成員函數(shù) —— 不需要對象的"獨(dú)立工作者"
靜態(tài)成員函數(shù)就更酷了,它不需要對象就能調(diào)用,就像上面例子里的showTotal()函數(shù)。
class MathHelper {
public:
static int add(int a, int b) {
return a + b;
}
static double pi() {
return 3.14159;
}
};
int main() {
// 直接用類名調(diào)用,不需要創(chuàng)建對象
cout << "5 + 3 = " << MathHelper::add(5, 3) << endl; // 輸出:8
cout << "π = " << MathHelper::pi() << endl; // 輸出:3.14159
return 0;
}
注意: 靜態(tài)成員函數(shù)里不能訪問非靜態(tài)成員,因為它根本不知道你要訪問哪個對象的成員!
第五招:靜態(tài)局部對象 —— 延遲加載的"懶漢"
這招比較高級,適合實(shí)現(xiàn)單例模式。對象只有在第一次被需要時才創(chuàng)建,之后就一直用這一個。
#include <iostream>
using namespace std;
class Singleton {
private:
Singleton() { cout << "單例對象創(chuàng)建了!" << endl; }
public:
static Singleton& getInstance() {
static Singleton instance; // 懶漢式創(chuàng)建
return instance;
}
void doSomething() {
cout << "我在做事情..." << endl;
}
};
int main() {
cout << "程序開始運(yùn)行" << endl;
Singleton& s1 = Singleton::getInstance(); // 這時候才創(chuàng)建對象
s1.doSomething();
Singleton& s2 = Singleton::getInstance(); // 不會再創(chuàng)建新對象
s2.doSomething();
return 0;
}
// 輸出:
// 程序開始運(yùn)行
// 單例對象創(chuàng)建了!
// 我在做事情...
// 我在做事情...
第六招:靜態(tài)常量成員 —— 類的"鐵律"
這招在實(shí)際開發(fā)中超級實(shí)用!有時候我們需要給類定義一些常量,比如最大值、版本號什么的,這時候static const就派上用場了。
#include <iostream>
using namespace std;
class GamePlayer {
private:
string name;
int level;
public:
// 這些是游戲的"鐵律",所有玩家都必須遵守
static const int MAX_LEVEL = 100; // 最高等級
static const int MIN_LEVEL = 1; // 最低等級
static constexpr double UPGRADE_RATE = 1.5; // 升級倍率
GamePlayer(string n) : name(n), level(1) {
cout << name << " 加入游戲,當(dāng)前等級:" << level << endl;
}
void upgrade() {
if (level < MAX_LEVEL) {
level += 2; // 每次升級增加2級,簡單直接
if (level > MAX_LEVEL) level = MAX_LEVEL;
cout << name << " 升級了!當(dāng)前等級:" << level << endl;
} else {
cout << name << " 已經(jīng)滿級了!" << endl;
}
}
static void showGameRules() {
cout << "=== 游戲規(guī)則 ===" << endl;
cout << "等級范圍:" << MIN_LEVEL << " - " << MAX_LEVEL << endl;
cout << "升級倍率:" << UPGRADE_RATE << endl;
}
};
int main() {
// 不需要創(chuàng)建對象就能查看游戲規(guī)則
GamePlayer::showGameRules();
GamePlayer player1("小明");
// 直接用類名訪問常量
cout << "游戲最高等級是:" << GamePlayer::MAX_LEVEL << endl;
// 升級幾次試試
player1.upgrade(); // 1 * 1.5 = 1
player1.upgrade(); // 1 * 1.5 = 1
return 0;
}
輸出結(jié)果:
=== 游戲規(guī)則 ===
等級范圍:1 - 100
升級倍率:1.5
小明 加入游戲,當(dāng)前等級:1
游戲最高等級是:100
小明 升級了!當(dāng)前等級:3
小明 升級了!當(dāng)前等級:5
這種用法的好處是:
- 靜態(tài)常量也屬于整個類,不占用每個對象的內(nèi)存
- 可以直接用類名訪問,非常方便
- 在編譯時就確定值,效率很高
- 所有對象共享同一套"規(guī)則"
總結(jié)一下,static的幾個"人設(shè)":
- 局部靜態(tài)變量 - 函數(shù)里的釘子戶,記住上次的值
- 全局靜態(tài)變量 - 文件里的獨(dú)行俠,只在本文件可見
- 靜態(tài)成員變量 - 類的公共財產(chǎn),所有對象共享
- 靜態(tài)成員函數(shù) - 獨(dú)立工作者,不需要對象就能調(diào)用
- 靜態(tài)局部對象 - 延遲加載的懶漢,用時才創(chuàng)建
- 靜態(tài)常量成員 - 類的鐵律,編譯時確定的共享常量
看完這些,你是不是發(fā)現(xiàn)static其實(shí)挺有意思的?它就像是C++里的一個"多面手",在不同的地方有不同的"人設(shè)",但核心思想都是控制生命周期和可見性。
下次再看到static,別再只想著"靜態(tài)變量"了,想想它到底在扮演什么角色,這樣代碼看起來會更清晰哦!
記住:程序員最重要的不是記住所有語法,而是理解每個工具的"性格",然后在合適的場合用合適的工具。static就是這樣一個很有"性格"的工具!