C++之const和static的使用及說明
本文將分別介紹const與static的用法,最后介紹兩者的結(jié)合應(yīng)用和常見坑點(diǎn)。
const:“只讀”的守護(hù)者
const 的核心作用是限制變量/對(duì)象的“可修改性”,強(qiáng)制編譯器檢查“意外修改”,本質(zhì)是給代碼加“安全鎖”。
它的用法圍繞“修飾誰”展開,不同修飾對(duì)象的含義完全不同,也是初學(xué)者最易踩坑的點(diǎn)。
修飾普通變量
- 作用:變量初始化后不可修改,編譯期會(huì)檢查賦值操作。
- 注意:必須在定義時(shí)初始化(局部/全局
const均需)。
示例:
const int max_len = 10; // 正確:定義時(shí)初始化 max_len = 20; // 錯(cuò)誤:編譯器直接報(bào)錯(cuò),禁止修改
修飾指針
const修飾指針關(guān)鍵看 const 和 * 的位置:
const int* p(const在*左邊):限制“指針指向的內(nèi)容”不可改,指針本身可以換指向。
int a = 5, b = 10; const int* p = &a; *p = 6; // 錯(cuò)誤:指向的內(nèi)容(a的值)不能改 p = &b; // 正確:指針可以指向新地址(b)
int* const p(const在*右邊):限制“指針本身”不可改,指向的內(nèi)容可以改。
int a = 5, b = 10; int* const p = &a; *p = 6; // 正確:指向的內(nèi)容(a的值)可以改 p = &b; // 錯(cuò)誤:指針不能換指向
修飾函數(shù)
修飾函數(shù)參數(shù):保證函數(shù)內(nèi)部不修改參數(shù)(尤其針對(duì)引用/指針參數(shù),避免意外篡改外部變量)。
// 傳入字符串,僅讀取不修改,用 const 保護(hù)
void printStr(const string& s) {
s += "test"; // 錯(cuò)誤:禁止修改 const 參數(shù)
cout << s << endl; // 正確:僅讀取
}
修飾函數(shù)返回值:限制返回值不可被修改(常見于返回指針/引用的場景,避免外部篡改內(nèi)部數(shù)據(jù))。
// 返回?cái)?shù)組首地址,禁止外部修改數(shù)組內(nèi)容
const int* getArr() {
static int arr[3] = {1,2,3};
return arr;
}
int main() {
const int* p = getArr();
*p = 4; // 錯(cuò)誤:返回值是 const,禁止修改
}
修飾類成員
const 成員變量:屬于對(duì)象的“常量”,必須在構(gòu)造函數(shù)初始化列表中初始化(不能在定義時(shí)直接賦值)。
class Person {
private:
const int age; // const 成員變量
public:
// 正確:在初始化列表中初始化
Person(int a) : age(a) {}
// 錯(cuò)誤:不能在構(gòu)造函數(shù)體內(nèi)賦值
// Person(int a) { age = a; }
};
const 成員函數(shù):保證函數(shù)內(nèi)部不修改任何非 mutable 成員變量,函數(shù)聲明和定義都要加 const。
class Person {
private:
int age;
public:
// 聲明時(shí)加 const
void showAge() const; //語法:返回值類型 函數(shù)名() const;
};
// 定義時(shí)也要加 const(位置不能錯(cuò))
void Person::showAge() const {
age = 20; // 錯(cuò)誤:const 函數(shù)禁止修改成員變量
cout << age << endl; // 正確:僅讀取
}
修飾對(duì)象
const 修飾對(duì)象,本質(zhì)是把對(duì)象變成 “只讀對(duì)象”—— 一旦定義,這個(gè)對(duì)象的成員變量就不能被修改,能有效保證數(shù)據(jù)安全(比如防止誤改關(guān)鍵數(shù)據(jù))。
- 格式很簡單:在對(duì)象定義前加
const,和定義const變量(比如const int a=10)的邏輯一致。
#include <iostream>
#include <string>
using namespace std;
// 定義一個(gè)學(xué)生類
class Student {
public:
string name; // 成員變量:姓名
int score; // 成員變量:成績
// 構(gòu)造函數(shù)(初始化姓名和成績)
Student(string n, int s) : name(n), score(s) {}
// 普通成員函數(shù):修改成績(可能改成員變量)
void setScore(int s) {
score = s;
}
// const 成員函數(shù):只打印信息(不修改成員變量)
void showInfo() const {
cout << "姓名:" << name << ",成績:" << score << endl;
}
};
int main() {
// 1. 普通對(duì)象(可以修改成員,調(diào)用任意函數(shù))
Student s1("張三", 90);
s1.score = 85; // 允許:普通對(duì)象能改成員變量
s1.setScore(88); // 允許:普通對(duì)象能調(diào)用非const函數(shù)
s1.showInfo(); // 允許:普通對(duì)象也能調(diào)用const函數(shù)
// 2. const對(duì)象(只讀,核心限制:不能改成員,只能調(diào)const函數(shù))
const Student s2("李四", 85);
// s2.score = 90; // 錯(cuò)誤!const對(duì)象不能直接修改成員變量
// s2.setScore(92); // 錯(cuò)誤!const對(duì)象不能調(diào)用非const函數(shù)
s2.showInfo(); // 允許!const對(duì)象只能調(diào)用const成員函數(shù)
return 0;
}
遵循兩個(gè)規(guī)則:
const對(duì)象的成員變量絕對(duì)不能修改。const對(duì)象只能調(diào)用const成員函數(shù)。
static:“靜態(tài)存儲(chǔ)”與“作用域控制”
static 的核心是改變變量/函數(shù)的“存儲(chǔ)周期”或“作用域”,本質(zhì)是管理“數(shù)據(jù)的生命周期”和“訪問范圍”,常見于“共享數(shù)據(jù)”“全局唯一”場景。
修飾全局變量
- 作用:全局
static變量的作用域僅限當(dāng)前.cpp文件,避免不同文件中“同名全局變量”的命名沖突。 - 對(duì)比普通全局變量:普通全局變量默認(rèn)“跨文件可見”(用
extern可引用),static全局變量則“文件私有”。
示例:
// a.cpp static int global_val = 5; // 僅 a.cpp 可見 // b.cpp extern int global_val; // 錯(cuò)誤:無法引用 a.cpp 的 static 全局變量
修飾局部變量
- 作用:局部
static變量的“作用域”仍在函數(shù)內(nèi),但“存儲(chǔ)周期”是整個(gè)程序(僅初始化一次,函數(shù)調(diào)用結(jié)束后不銷毀)。 - 典型場景:函數(shù)內(nèi)的計(jì)數(shù)器、全局唯一的臨時(shí)數(shù)據(jù)。
示例:
void countCall() {
static int cnt = 0; // 僅初始化一次(第一次調(diào)用時(shí))
cnt++;
cout << "調(diào)用次數(shù):" << cnt << endl;
}
int main() {
countCall(); // 輸出 1
countCall(); // 輸出 2(cnt 未被銷毀)
}
修飾類成員
static 類成員是“所有對(duì)象共享的數(shù)據(jù)/方法”,不依賴具體對(duì)象存在。
static 成員變量
- 特點(diǎn):屬于整個(gè)類,所有對(duì)象共用同一內(nèi)存,必須在類外單獨(dú)初始化(不能在構(gòu)造函數(shù)中初始化)。由于static成員變量存儲(chǔ)在類的外部,計(jì)算類的大小時(shí)不包含在內(nèi)。
示例:統(tǒng)計(jì)類的對(duì)象創(chuàng)建個(gè)數(shù)
class Student {
private:
static int total; // 聲明:屬于 Student 類
public:
Student() { total++; } // 創(chuàng)建對(duì)象時(shí)計(jì)數(shù)+1
~Student() { total--; } // 銷毀對(duì)象時(shí)計(jì)數(shù)-1
// 必須用 static 函數(shù)訪問 static 變量(見下文)
static int getTotal() { return total; }
};
// 類外初始化:不加 static,需指定類名
int Student::total = 0;
int main() {
Student s1, s2;
cout << Student::getTotal(); // 輸出 2(兩個(gè)對(duì)象)
}
static成員函數(shù)
- 特點(diǎn):沒有
this指針(因?yàn)椴灰蕾噷?duì)象),只能訪問static成員變量/函數(shù),不能訪問非static成員。 - 調(diào)用方式:直接用“類名::函數(shù)名”調(diào)用(無需創(chuàng)建對(duì)象)。
- 示例:上文
Student::getTotal(),直接通過類名調(diào)用。
const 與 static 結(jié)合應(yīng)用
兩者結(jié)合的核心場景是“類的靜態(tài)常量”,即 static const(或 const static,兩者在類中等價(jià)),用于定義“類級(jí)別的常量”(所有對(duì)象共用,且不可修改),既實(shí)現(xiàn)了數(shù)據(jù)共享又達(dá)到了數(shù)據(jù)不可被改變的目的。
關(guān)鍵用法:類內(nèi)靜態(tài)常量的初始化
C++11 及以后:static const 成員變量可在類內(nèi)直接初始化(僅限字面量類型,如 int、char 等)。
示例:
class Config {
public:
// C++11+ 支持:類內(nèi)直接初始化靜態(tài)常量
static const int MAX_NUM = 100;
static const string DEFAULT_NAME; // 非字面量類型,需類外初始化
};
// 非字面量類型的 static const 成員,仍需類外初始化
const string Config::DEFAULT_NAME = "unknown";
注意:C++11 前,static const 成員變量必須在類外初始化,即使是字面量類型。
避坑指南
坑 1:const 變量能“強(qiáng)制修改”?
用指針強(qiáng)制轉(zhuǎn)換可以修改 const 變量,但這是“未定義行為”(編譯器不報(bào)錯(cuò),但運(yùn)行結(jié)果不可控,可能觸發(fā)崩潰),絕對(duì)禁止!
const int a = 5; int* p = (int*)&a; // 強(qiáng)制轉(zhuǎn)換(危險(xiǎn)?。? *p = 10; // 運(yùn)行時(shí)可能修改成功,但屬于未定義行為
坑 2:static 局部變量的線程安全?
- C++11 及以后:
static局部變量的初始化是“線程安全”的(編譯器會(huì)加鎖,避免多線程同時(shí)初始化)。 - C++11 前:非線程安全,多線程同時(shí)調(diào)用可能導(dǎo)致重復(fù)初始化。
坑 3:類 static 成員忘記類外初始化?
僅在類內(nèi)聲明 static 成員變量,未在類外初始化,會(huì)導(dǎo)致鏈接錯(cuò)誤(編譯器找不到變量的定義)。記住:static 類成員“聲明在類內(nèi),定義在類外”。
結(jié)尾總結(jié)
const 和 static 雖基礎(chǔ),但用法靈活,核心記住兩點(diǎn):
- const:圍繞“只讀”,為代碼加安全鎖,避免意外修改(重點(diǎn)分清修飾指針的兩種場景、類 const 成員的初始化)。
- static:圍繞“靜態(tài)存儲(chǔ)/作用域”,管理數(shù)據(jù)生命周期(重點(diǎn)掌握類 static 成員的“類外初始化”和“共享特性”)。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
如何在C++中實(shí)現(xiàn)一個(gè)正確的時(shí)間循環(huán)器詳解
這篇文章主要給大家介紹了關(guān)于如何在C++中實(shí)現(xiàn)一個(gè)正確的時(shí)間循環(huán)器的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
C/C++實(shí)現(xiàn)的游戲角色名稱名字隨機(jī)生成代碼
這篇文章主要介紹了C/C++實(shí)現(xiàn)的游戲角色名稱名字隨機(jī)生成代碼,本文特別針對(duì)一些古典游戲的角色名稱進(jìn)行隨機(jī)生成,需要的朋友可以參考下2015-05-05
一篇文章帶你用C語言玩轉(zhuǎn)結(jié)構(gòu)體
本文主要介紹C語言 結(jié)構(gòu)體的知識(shí),學(xué)習(xí)C語言肯定需要學(xué)習(xí)結(jié)構(gòu)體,這里詳細(xì)說明了結(jié)構(gòu)體并附示例代碼,供大家參考學(xué)習(xí),有需要的小伙伴可以參考下2021-09-09

