C++: static
1 人贊了文章
- 限制作用域: static全局變數和函數,其作用域為當前cpp文件,其它的cpp文件不能訪問該變數和函數。
- 類的static 數據成員/成員函數: 表示屬於一個類而不是屬於此類的任何特定對象的變數和函數。比如在對某一個類的對象進行計數時, 計數生成多少個類的實例, 就可以用到靜態數據成員
-----------------------------------------------
c/c++ static 用法總結(三版本合一)
static
2、限制作用域
這一點相對於普通全局變數和static全局變數來說的。
對於全局變數而言,不論是普通全局變數還是static全局變數,其存儲區都是靜態存儲區
,因此在內存分配上沒有什麼區別。
區 別在於:
1) 普通的全局變數和函數,其作用域為整個程序或項目,外部文件(其它cpp文件)可以
通過extern關鍵字訪問該變數和函數。一般不提倡這種用法,如果要在多個cpp文件間共享
數據,應該將數據聲明為extern類型。
在頭文件里聲明為extern:
extern int g_value; // 注意,不要初始化值!
然後在其中任何一個包含該頭文件的cpp中初始化(一次)就好:
int g_value = 0; // 初始化一樣不要extern修飾,因為extern也是聲明性關鍵字;
然後所有包含該頭文件的cpp文件都可以用g_value這個名字訪問相同的一個變數;
2) static全局變數和函數,其作用域為當前cpp文件,其它的cpp文件不能訪問該變數和
函數。如果有兩個cpp文件聲明了同名的全局靜態變數,那麼他們實際上是獨立的兩個變數.
static函數的好處是不同的人編寫不同的函數時,不用擔心自己定義的函數,是否會與其它文件中的函數同名。
頭文件中的static變數如果在一個頭文件中聲明:
static int g_vaule = 0;
那麼會為每個包含該頭文件的cpp都創建一個全局變數,但他們都是獨立的;所以也
不建議這樣的寫法,一樣不明確需要怎樣使用這個變數,因為只是創建了一組同名而不同
作用域的變數.
3、數據唯一性
static data member, static method in class
a.hclass A {....private: A my_map_ = new std::unordered_map<string, string>;}a.cc void A::f() {my_map_->insert(..);} will cause memory leakage, because every time a instance of A is created, memory is allocated. Need to use static, only allocate once, and shared among instances of class A.a.hclass A {....private: A my_map_;}//a.cc static A::my_map_ = new std::unordered_map<string, string>;void A::GenerateMyMap() { my_map_->insert(..);}
Its better to just initiate the map while defining it.
//module.ccnamespace youku {namespace scoring {using DataSource;namespace {const std::unordered_map<string, string>& GenerateMap() { // This map will be initiated only one time. And shared among instances of this class static auto* map = new std::unordered_map<string, string>({{"key1", "val1"}, {"key2", "val2"}});return *map;}} // namespaceMyClass::MyMethod() { const auto* val = FindOrNull(GenerateMap(), "key1"); }} // namespace scoring} // namespace youku
這是C++對static關鍵字的重用。主要指靜態數據成員/成員函數。
表示屬於一個類而不是屬於此類的任何特定對象的變數和函數. 這是與普通成員函數的最
大區別, 也是其應用所在, 比如在對某一個類的對象進行計數時, 計數生成多少個類的實
例, 就可以用到靜態數據成員. 在這裡面, static既不是限定作用域的, 也不是擴展生存
期的作用, 而是指示變數/函數在此類中的唯一性. 這也是」屬於一個類而不是屬於此類的
任何特定對象的變數和函數」的含義. 因為它是對整個類來說是唯一的, 因此不可能屬於
某一個實例對象的. (針對靜態數據成員而言, 成員函數不管是否是static, 在內存中只有
一個副本, 普通成員函數調用時, 需要傳入this指針, static成員函數調用時, 沒有this
指針. )
static數據成員的初始化:
(1) 初始化在類體外進行,而前面不加static,以免與一般靜態變數或對象相混淆。
(2) 初始化時不加該成員的訪問許可權控制符private,public等。
(3) 初始化時使用作用域運算符來標明它所屬類,因此,靜態數據成員是類的成員,而不
是對象的成員。
(4) 靜態數據成員是靜態存儲的,它是靜態生存期,必須對它進行初始化。
Static成員函數靜態成員函數和靜態數據成員一樣,它們都屬於類的靜態成員,它們都不是對象成員。因
此,對靜態成員的引用不需要用對象名。
靜態成員函數僅能訪問靜態的數據成員,不能訪問非靜態的數據成員,也不能訪問非靜態
的成員函數,這是由於靜態的成員函數沒有this指針。
------------------
(1)先來介紹它的第一條也是最重要的一條:隱藏。
當我們同時編譯多個文件時,所有未加static前綴的全局變數和函數都具有全局可見性。為理解這句話,我舉例來說明。我們要同時編譯兩個源文件,一個是a.c,另一個是main.c。
下面是a.c的內容
char a = A; // global variablevoid msg(){ printf("Hello
");}
下面是main.c的內容
int main(void){ extern char a; // extern variable must be declared before use printf("%c ", a); (void)msg(); return 0;}
程序的運行結果是:
A Hello
你可能會問:為什麼在a.c中定義的全局變數a和函數msg能在main.c中使用?前面說過,所有未加static前綴的全局變數和函數都具有全局可見性,其它的源文件也能訪問。此例中,a是全局變數,msg是函數,並且都沒有加static前綴,因此對於另外的源文件main.c是可見的。
如果加了static,就會對其它源文件隱藏。例如在a和msg的定義前加上static,main.c就看不到它們了。利用這一特性可以在不同的文件中定義同名函數和同名變數,而不必擔心命名衝突。Static可以用作函數和變數的前綴,對於函數來講,static的作用僅限於隱藏,而對於變數,static還有下面兩個作用。
(2)static的第二個作用是保持變數內容的持久。存儲在靜態數據區的變數會在程序剛開始運行時就完成初始化,也是唯一的一次初始化。共有兩種變數存儲在靜態存儲區:全局變數和static變數,只不過和全局變數比起來,static可以控制變數的可見範圍,說到底static還是用來隱藏的。雖然這種用法不常見,但我還是舉一個例子。
#include <stdio.h>int fun(void){ static int count = 10; // local static return count--;}int count = 1; // globalint main(void){ printf("global local static
"); for(; count <= 10; ++count) printf("%d %d
", count, fun()); return 0;}
程序的運行結果是:
global local static1 102 93 84 75 66 57 48 39 210 1
#include <stdio.h>int a;int main(void){ int i; static char str[10]; printf("integer: %d; string: (begin)%s(end)", a, str); return 0;}
程序的運行結果如下
integer: 0; string: (begin)(end)
最後對static的三條作用做一句話總結。首先static的最主要功能是隱藏,其次因為static變數存放在靜態存儲區,所以它具備持久性和默認值0。
推薦閱讀:
※php 與C/C++ 集成的方法有哪些?
※簡析 Python 的 `NotImplemented`
※字元指針數組的使用--替換人名-題目分析
※C#中使用Lambda表達式簡化代碼