C++之靜態(tài)函數(shù)用法及說明
類中的靜態(tài)函數(shù),就是屬于“類本身”的函數(shù),不屬于某一個具體對象。
最典型的寫法是:
class ZlogBase
{
public:
static void Initialize(const std::string& config_path);
static void Shutdown();
};
這兩個函數(shù)前面有 static,它們就是靜態(tài)成員函數(shù)。
一、怎么使用
靜態(tài)函數(shù)最常見的調(diào)用方式是:
ZlogBase::Initialize("log.conf");
ZlogBase::Shutdown();
也就是:
類名::函數(shù)名()
因為它屬于類本身,所以不需要先創(chuàng)建對象。
對比一下普通成員函數(shù)
普通成員函數(shù):
class ZlogBase
{
public:
void logInfo(const char* msg) const;
};
這種函數(shù)必須通過對象調(diào)用:
ZlogBase logger("tcpserver");
logger.logInfo("server start");
不能直接:
ZlogBase::logInfo("server start"); // 錯
因為 logInfo() 需要依賴某個對象內(nèi)部的數(shù)據(jù),比如:
m_pZlogCategorythis
二、為什么靜態(tài)函數(shù)可以直接用類名調(diào)用
因為靜態(tài)函數(shù)沒有 this 指針。
普通成員函數(shù)在內(nèi)部其實默認(rèn)都帶著一個隱藏參數(shù):
this
表示“當(dāng)前對象是誰”。
比如:
logger.logInfo("hello");
本質(zhì)上像是:
logger.logInfo(&logger, "hello");
只是這個 this 是編譯器自動傳進去的。
但是靜態(tài)函數(shù)沒有 this,所以它不能訪問對象成員變量,也不依賴某個對象。
既然它不依賴對象,那就可以直接:
ZlogBase::Initialize(...)
三、靜態(tài)函數(shù)里能做什么,不能做什么
能做的
可以做和“整個類”有關(guān)、但和“某個具體對象”無關(guān)的事情。
例如:
- 全局初始化
- 全局釋放
- 計數(shù)器
- 工具函數(shù)
- 工廠函數(shù)
- 單例訪問入口
不能直接做的
不能直接訪問普通成員變量,比如:
class ZlogBase
{
protected:
zlog_category_t* m_pZlogCategory = nullptr;
public:
static void Initialize(const std::string& config_path);
};
在 Initialize() 里不能直接寫:
m_pZlogCategory = ...; // 錯
因為 m_pZlogCategory 屬于某個對象,
而靜態(tài)函數(shù)不知道你想操作哪個對象。
四、為什么Initialize()適合做成靜態(tài)函數(shù)
你現(xiàn)在這個例子最典型:
ZlogBase::Initialize(LOG_FILE_PATH);
因為“初始化日志系統(tǒng)”這件事,本質(zhì)上是整個程序級別的事情,不是某一個 TcpServer 或某一個 System 對象自己的事情。
它通常做的是:
zlog_init(LOG_FILE_PATH);
這是全局初始化。
所以它很適合寫成:
static void Initialize(...);
這樣你在 main() 里程序啟動時就能先調(diào)用:
ZlogBase::Initialize(LOG_FILE_PATH);
后面再去創(chuàng)建:
SystemTcpServerDevInfo
這些對象。
五、為什么要“先 Initialize,再創(chuàng)建對象”
因為很多對象在構(gòu)造時就要用日志。
比如:
class TcpServer : public ZlogBase
{
public:
TcpServer() : ZlogBase("tcpserver") {}
};
而 ZlogBase("tcpserver") 里面可能會調(diào)用:
zlog_get_category("tcpserver");
那前提就是:
zlog 系統(tǒng)已經(jīng)先初始化好了。
所以順序必須是:
ZlogBase::Initialize(...); // 先初始化整個日志系統(tǒng) TcpServer server; // 再創(chuàng)建具體對象
這就是為什么 Initialize() 設(shè)計成靜態(tài)函數(shù),并且在 main() 里直接調(diào)用最合理。
六、一個非常好理解的類比
比如學(xué)校系統(tǒng):
class Student
{
public:
static void SetSchoolName(const std::string& name);
void SetStudentName(const std::string& name);
};
學(xué)校名稱
這是所有學(xué)生共享的,屬于“整個類”的事情,所以適合靜態(tài)函數(shù):
Student::SetSchoolName("No.1 Middle School");
學(xué)生姓名
這是某個具體學(xué)生自己的事情,所以必須通過對象:
Student s;
s.SetStudentName("Tom");
ZlogBase::Initialize()就像“設(shè)置學(xué)校名字”,是全局動作。logInfo()就像“設(shè)置學(xué)生名字”,是對象動作。
七、靜態(tài)函數(shù)常見使用場景
在實際項目里,靜態(tài)函數(shù)常見于這幾類:
1. 全局初始化 / 釋放
像你這個:
ZlogBase::Initialize(...); ZlogBase::Shutdown();
2. 計數(shù)器
class Test
{
public:
static int Count();
};
統(tǒng)計一共創(chuàng)建了多少對象之類。
3. 工具函數(shù)
class Math
{
public:
static int Add(int a, int b);
};
直接:
Math::Add(1, 2);
不需要先創(chuàng)建 Math 對象。
4. 單例入口
class Config
{
public:
static Config& instance();
};
八、靜態(tài)函數(shù)和靜態(tài)成員變量經(jīng)常配合使用
例如:
class ZlogBase
{
public:
static void Initialize(const std::string& path);
private:
static bool s_inited;
};
這里:
Initialize()是靜態(tài)函數(shù)s_inited是靜態(tài)變量
這兩個都屬于類本身,而不是某個對象。
所以非常適合做“全局只初始化一次”的邏輯。
九、你現(xiàn)在這個例子應(yīng)該怎么理解
你截圖里的:
QCoreApplication a(argc, argv); ZlogBase::Initialize(LOG_FILE_PATH); System* pApp = new System(); pApp->Init();
應(yīng)該理解成:
第一步
程序啟動,先初始化日志系統(tǒng):
ZlogBase::Initialize(LOG_FILE_PATH);
第二步
再創(chuàng)建系統(tǒng)對象:
System* pApp = new System();
如果 System 繼承了 ZlogBase,那它在構(gòu)造時就能安全使用日志功能。
十、一句話總結(jié)
靜態(tài)函數(shù)用于處理“屬于整個類、而不屬于某個具體對象”的事情。
所以像:
- 初始化日志系統(tǒng)
- 關(guān)閉日志系統(tǒng)
這種全局動作,最適合寫成:
ZlogBase::Initialize(...); ZlogBase::Shutdown();
而像:
logInfo()logError()
這種依賴對象內(nèi)部狀態(tài)的函數(shù),就必須通過對象調(diào)用。
如果你愿意,我下一條可以繼續(xù)專門講一下:
靜態(tài)成員變量和靜態(tài)成員函數(shù)的關(guān)系,以及它們在 .h / .cpp 里應(yīng)該怎么寫。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
C/C++表格組件Qt?TableWidget應(yīng)用詳解
本文詳細(xì)講解了C/C++中使用列表框組件Qt?TableWidget的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12
C++異步操作future和aysnc與function和bind
這篇文章主要介紹了C++異步操作future和aysnc與function和bind,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-09-09
Windows下ncnn環(huán)境配置教程詳解(VS2019)
這篇文章主要介紹了Windows下ncnn環(huán)境配置(VS2019),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03

