① C璇璦涓璼tatic鏄鍋氫粈涔堢敤鐨勶紵
鏈変袱縐嶇敤娉曪細
1銆乻tatic淇楗板矓閮ㄥ彉閲忥紝鎴愪負涓涓灞閮ㄩ潤鎬佸彉閲忋
static淇楗板矓閮ㄥ彉閲(闈欐佸矓閮ㄥ彉閲)涓庢櫘閫氬矓閮ㄥ彉閲忕浉姣旓紝瀹冪殑浼樺娍鍦ㄤ簬錛
鈶犻潤鎬佸矓閮ㄥ彉閲忎綔鐢ㄥ煙涓庤繛鎺ュ睘鎬т笌鏅閫氬矓閮ㄥ彉閲忎竴鏍鳳紱
鈶″瓨鍌ㄧ被錛氶潤鎬佸矓閮ㄥ彉閲忓垎閰嶅湪data/bss孌碉紝鏅閫氬矓閮ㄥ彉閲忓湪鏍堜笂錛
鈶㈢敓鍛藉懆鏈燂細鍥犱負瀛樺偍綾葷殑涓嶅悓錛岄潤鎬佸矓閮ㄥ彉閲忕殑鐢熷懡鍛ㄦ湡寰楀埌寤墮暱浜嗭紝鐩村埌紼嬪簭緇撴潫銆
2銆乻tatic淇楗板叏灞鍙橀噺涓庡嚱鏁幫紝鎴愪負闈欐佸叏灞鍙橀噺涓庨潤鎬佸嚱鏁般
static淇楗板叏灞鍙橀噺鍑芥暟 涓 鏅閫氬叏灞鍙橀噺鏅閫氬嚱鏁扮浉姣旓紝瀹冪殑浼樺娍鍦ㄤ簬錛
鈶犲瓨鍌ㄧ被銆佺敓鍛藉懆鏈熴佷綔鐢ㄥ煙閮戒竴鏍鳳紱
鈶″樊鍒鍦ㄤ簬static淇楗板叏灞鍙橀噺鍑芥暟榪炴帴灞炴ф槸鍐呰繛鎺ワ紝鏅閫氬叏灞鍙橀噺鏅閫氬嚱鏁版槸澶栭摼鎺ワ紱
鈶㈠氨鏄璇磗tatic淇楗板叏灞鍙橀噺鍑芥暟涓嶈兘璺ㄦ枃浠惰塊棶璋冪敤銆
鎵╁睍璧勬枡錛
鍦ㄧ被鍐呮暟鎹鎴愬憳鐨勫0鏄庡墠鍔犱笂static鍏抽敭瀛楋紝璇ユ暟鎹鎴愬憳灝辨槸綾誨唴鐨勯潤鎬佹暟鎹鎴愬憳銆傚叾鐗圭偣濡備笅錛
闈欐佹暟鎹鎴愬憳瀛樺偍鍦ㄥ叏灞鏁版嵁鍖猴紝闈欐佹暟鎹鎴愬憳鍦ㄥ畾涔夋椂鍒嗛厤瀛樺偍絀洪棿錛屾墍浠ヤ笉鑳藉湪綾誨0鏄庝腑瀹氫箟
闈欐佹暟鎹鎴愬憳鏄綾葷殑鎴愬憳錛屾棤璁哄畾涔変簡澶氬皯涓綾葷殑瀵硅薄錛岄潤鎬佹暟鎹鎴愬憳鐨勬嫹璐濆彧鏈変竴涓錛屼笖瀵硅ョ被鐨勬墍鏈夊硅薄鍙瑙併備篃灝辨槸璇翠換涓瀵硅薄閮藉彲浠ュ歸潤鎬佹暟鎹鎴愬憳榪涜屾搷浣溿傝屽逛簬闈為潤鎬佹暟鎹鎴愬憳錛屾瘡涓瀵硅薄閮芥湁鑷宸辯殑涓浠芥嫹璐濄
鐢變簬涓婇潰鐨勫師鍥狅紝闈欐佹暟鎹鎴愬憳涓嶅睘浜庝換浣曞硅薄錛屽湪娌℃湁綾葷殑瀹炰緥鏃跺叾浣滅敤鍩熷氨鍙瑙侊紝鍦ㄦ病鏈変換浣曞硅薄鏃訛紝灝卞彲浠ヨ繘琛屾搷浣
鍜屾櫘閫氭暟鎹鎴愬憳涓鏍鳳紝闈欐佹暟鎹鎴愬憳涔熼伒浠巔ublic, protected, private璁塊棶瑙勫垯
闈欐佹暟鎹鎴愬憳鐨勫垵濮嬪寲鏍煎紡錛<鏁版嵁綾誨瀷><綾誨悕>::<闈欐佹暟鎹鎴愬憳鍚>=<鍊>
綾葷殑闈欐佹暟鎹鎴愬憳鏈変袱縐嶈塊棶鏂瑰紡錛<綾誨硅薄鍚>.<闈欐佹暟鎹鎴愬憳鍚> 鎴 <綾葷被鍨嬪悕>::<闈欐佹暟鎹鎴愬憳鍚>
② java! static什麼作用
static是靜態修飾符,static可以用來區分成員變數、方法是屬於類本身還是屬於類實例內化後的對象。有static修飾容的成員屬於類本身,沒有static修飾的成員屬於類的實例。
static靜態變數是屬於類的,只有一份存儲空間,是類之間共享的,牽一發而動全身,一處變,處處變。實例變數屬於實例對象,創建幾次對象,就有幾份的成員變數(拷貝)。
(2)javacstatic擴展閱讀
static的使用
示例:
classa{
publicstatic$aa=1;
publicstaticfunctionaa(){
self::$aa+=1;
echoself::$aa;
}
}
classb{
publicfunctionbb(){
a::aa();
}
}
classc{
publicfunctioncc(){
a::aa();
}
}
$bbb=newb();
$ccc=newc();
$bbb->bb();
echo'*******************';
$ccc->cc();
③ java中static的用法
1.靜態方法
通常,在一個類中定義一個方法為static,那就是說,無需本類的對象即可調用此方法
聲明為static的方法有以下幾條限制:
·它們僅能調用其他的static 方法。
·它們只能訪問static數據。
·它們不能以任何方式引用this 或super。
class Simple {
staticvoid go() {
System.out.println("Welcome");
}
}
publicclass Cal {
publicstaticvoid main(String[] args) {
Simple.go();
}
}
調用一個靜態方法就是「類名.方法名」,靜態方法的使用很簡單如上所示。一般來說,靜態方法常常為應用程序中的其它類提供一些實用工具所用,在Java的類庫中大量的靜態方法正是出於此目的而定義的。
2.靜態變數
聲明為static的變數實質上就是全局變數。當聲明一個對象時,並不產生static變數的拷貝,而是該類所有的實例變數共用同一個static變數。靜態變數與靜態方法類似。所有此類實例共享此靜態變數,也就是說在類裝載時,只分配一塊存儲空間,所有此類的對象都可以操控此塊存儲空間,當然對於final則另當別論了
class Value {
staticintc = 0;
staticvoid inc() {
c++;
}
}
publicclass Count2 {
publicstaticvoid prt(String s) {
System.out.print(s);
}
publicstaticvoid main(String[] args) {
Value v1, v2;
v1 = new Value();
v2 = new Value();
prt("v1.c=" + v1.c + " v2.c=" + v2.c);
v1.inc();
prt(" v1.c=" + v1.c + " v2.c=" + v2.c);
}
}
結果為:v1.c=0 v2.c=0 v1.c=1 v2.c=1
由此可以證明它們共享一塊存儲區。static變數有點類似於C中的全局變數的概念。
值得探討的是靜態變數的初始化問題。
如果你需要通過計算來初始化你的static變數,你可以聲明一個static塊,Static 塊僅在該類被載入時執行一次。下面的例子顯示的類有一個static方法,一些static變數,以及一個static 初始化塊:
class Value3 {
staticintc = 0;
Value3() {
c = 15;
}
Value3(int i) {
c = i;
}
staticvoid inc() {
c++;
}
}
publicclass Count {
publicstaticvoid prt(String s) {
System.out.println(s);
}
Value3 v = new Value3(10);
static Value3 v1, v2;
static {//此即為static塊
prt("v1.c=" + v1.c + " v2.c=" + v2.c);
v1 = new Value3(27);
prt("v1.c=" + v1.c + " v2.c=" + v2.c);
v2 = new Value3(15);
prt("v1.c=" + v1.c + " v2.c=" + v2.c);
}
publicstaticvoid main(String[] args) {
Count ct = new Count();
prt("ct.c=" + ct.v.c);
prt("v1.c=" + v1.c + " v2.c=" + v2.c);
v1.inc();
prt("v1.c=" + v1.c + " v2.c=" + v2.c);
prt("ct.c=" + ct.v.c);
}
}
結果為:
v1.c=0 v2.c=0
v1.c=27 v2.c=27
v1.c=15 v2.c=15
ct.c=10
v1.c=10 v2.c=10
v1.c=11 v2.c=11
ct.c=11
這個程序展示了靜態初始化的各種特性。如果你初次接觸Java,結果可能令你吃驚。可能會對static後加大括弧感到困惑。首先要告訴你的是,static定義的變數會優先於任何其它非static變數,不論其出現的順序如何。正如在程序中所表現的,雖然v出現在v1和v2的前面,但是結果卻是v1和v2的初始化在v的前面。在static{後面跟著一段代碼,這是用來進行顯式的靜態變數初始化,這段代碼只會初始化一次,且在類被第一次裝載時。如果你能讀懂並理解這段代碼,會幫助你對static關鍵字的認識。在涉及到繼承的時候,會先初始化父類的static變數,然後是子類的,依次類推。
3.靜態類
通常一個普通類不允許聲明為靜態的,只有一個內部類才可以。這時這個聲明為靜態的內部類可以直接作為一個普通類來使用,而不需實例一個外部類。
publicclass StaticCls {
publicstaticvoid main(String[] args) {
OuterCls.InnerCls oi = newOuterCls.InnerCls();
}
}
classOuterCls {
publicstaticclass InnerCls {
InnerCls() {
System.out.println("InnerCls");
}
}
}
結果為:InnerCls
④ static 鍙橀噺 鍜 static 鍑芥暟鍚勬湁浠涔堢壒鐐
1)銆佸彉閲忔斁紼嬪簭鍏ㄥ矓瀛樺偍鍖鴻皟鐢ㄥ欎繚鎸佸師璧嬪肩偣涓庡爢鏍堝彉閲忓爢鍙橀噺鍖哄埆
2)銆佸彉閲忕敤static鍛婄煡緙栬瘧鍣鑷浠呬粎鍙橀噺浣滅敤鑼冨洿鍐呰佺偣涓鍏ㄥ矓鍙橀噺鍖哄埆
Tips:
A.鑻ュ叏灞鍙橀噺浠呭崟C鏂囦歡璁塊棶鍒欏彉閲忎慨鏀歸潤鎬佸叏灞鍙橀噺闄嶄綆妯″潡闂鑰﹀悎搴;
B.鑻ュ叏灞鍙橀噺浠呯敱鍗曞嚱鏁璁塊棶鍒欏彉閲忔敼璇ュ嚱鏁伴潤鎬佸矓閮ㄥ彉閲忛檷浣庢ā鍧楅棿鑰﹀悎搴;
C.璁捐′嬌鐢ㄨ塊棶鎬佸叏灞鍙橀噺銆侀潤鎬佸叏灞鍙橀噺銆侀潤鎬佸矓閮ㄥ彉閲忓嚱鏁伴渶瑕佽冭檻閲嶅叆闂棰;
D.鎴戦渶瑕侀噸鍏ュ嚱鏁版垜瀹氳侀伩鍏嶅嚱鏁頒嬌鐢╯tatic鍙橀噺(鍑芥暟縐:甯鍐呴儴瀛樺偍鍣鍔熻兘鍑芥暟)
E.鍑芥暟蹇呴』瑕佷嬌鐢╯tatic鍙橀噺鎯呭喌:姣旀煇鍑芥暟榪斿兼寚閽堢被鍨嬪垯蹇呴』static灞閮ㄥ彉閲忓潃浣滆繑鍊艱嫢auto綾誨瀷鍒欒繑閿欐寚閽
鍑芥暟鍓嶅姞static浣垮嚱鏁伴潤鎬佸嚱鏁板剆tatic鍚涔夋寚瀛樺偍寮忔寚鍑芥暟浣滅敤鍩熶粎灞闄愪簬鏈鏂囦歡(鎵縐板唴閮ㄥ嚱鏁)浣跨敤鍐呴儴鍑芥暟澶:鍚岀紪鍐欏悓鍑芥暟鐢ㄦ媴鑷瀹氫箟鍑芥暟鍚︿笌鍏舵枃浠跺嚱鏁板悓鍚
鎵╁睍鏋:鏈璇璼tatic鐫瀵誨巻鍙.璧峰垵C寮曞叆鍏抽敭瀛梥tatic琛ㄧず閫鍧椾粛瀛樺矓閮ㄥ彉閲忛殢staticC絎浜岀嶅惈涔:鐢ㄨ〃紺鴻兘鍏舵枃浠惰塊棶鍏ㄥ矓鍙橀噺鍑芥暟閬垮厤寮曞叆鏂板叧閿瀛楁墍浠嶄嬌鐢╯tatic鍏抽敭瀛楄〃紺虹浜岀嶅惈涔塁++閲嶇敤鍏抽敭瀛楀苟璧嬩簣涓庡墠闈㈠悓絎涓夌嶅惈涔:琛ㄧず灞炰簬綾誨睘浜庣被浠諱綍鐗瑰畾璞″彉閲忓嚱鏁(涓嶫ava鍏抽敭瀛楀惈涔夌浉鍚)
鍏ㄥ矓鍙橀噺銆侀潤鎬佸叏灞鍙橀噺銆侀潤鎬佸矓閮ㄥ彉閲忓矓閮ㄥ彉閲忓尯鍒鍙橀噺:鍏ㄥ矓鍙橀噺銆侀潤鎬佸叏灞鍙橀噺銆侀潤鎬佸矓閮ㄥ彉閲忓矓閮ㄥ彉閲
鎸夊瓨鍌ㄥ尯鍩熷叏灞鍙橀噺銆侀潤鎬佸叏灞鍙橀噺闈欐佸矓閮ㄥ彉閲忛兘瀛樻斁鍐呭瓨闈欐佸瓨鍌ㄥ尯鍩熷矓閮ㄥ彉閲忓瓨鏀懼唴瀛樻爤鍖
鎸変綔鐢ㄥ煙鍏ㄥ矓鍙橀噺鏁村伐紼嬫枃浠跺唴閮芥晥;闈欐佸叏灞鍙橀噺瀹氫箟鏂囦歡鍐呮晥;闈欐佸矓閮ㄥ彉閲忓畾涔夊嚱鏁板唴鏁堢▼搴忎粎閰嶅唴瀛樺嚱鏁拌繑璇ュ彉閲忔秷澶;灞閮ㄥ彉閲忓畾涔夊嚱鏁板唴鏁堝嚱鏁拌繑澶辨晥鍏ㄥ矓鍙橀噺(澶栭儴鍙橀噺)璇存槑鍓嶅啀鍐爏tatic
鏋勯潤鎬佸叏灞鍙橀噺鍏ㄥ矓鍙橀噺鏈韜闈欐佸瓨鍌ㄥ紡
闈欐佸叏灞鍙橀噺闈欐佸瓨鍌ㄥ紡
涓よ呭瓨鍌ㄥ紡騫跺悓涓よ呭尯鍒鉶戒簬闈為潤鎬佸叏灞鍙橀噺浣滅敤鍩熸暣婧愮▼搴
婧愮▼搴忕敱婧愭枃浠緇勯潪闈欐佸叏灞鍙橀噺鍚勬簮鏂囦歡閮芥晥
闈欐佸叏灞鍙橀噺鍒欓檺鍒跺叾浣滅敤鍩
鍗沖畾涔夎ュ彉閲忔簮鏂囦歡鍐呮晥
鍚屾簮紼嬪簭鍏舵簮鏂囦歡鑳戒嬌鐢ㄧ敱浜庨潤鎬佸叏灞鍙橀噺浣滅敤鍩熷矓闄愪簬婧愭枃浠跺唴鑳借ユ簮鏂囦歡鍐呭嚱鏁板叕鐢
閬垮厤鍏舵簮鏂囦歡寮曡搗閿欒
鏋愮湅
灞閮ㄥ彉閲忔敼鍙闈欐佸彉閲鏀瑰彉瀛樺偍寮忓嵆鏀瑰彉瀛樻湡鍏ㄥ矓鍙橀噺鏀瑰彉闈欐佸彉閲忔敼鍙樹綔鐢ㄥ煙
闄愬埗浣跨敤鑼冨洿
static鍑芥暟涓庢櫘閫氬嚱鏁頒綔鐢ㄥ煙鍚屼粎鏈鏂囦歡鍓嶆簮鏂囦歡浣跨敤鍑芥暟搴旇ヨ存槑鍐呴儴鍑芥暟(static)鍐呴儴鍑芥暟搴旇ュ墠婧愭枃浠惰存槑瀹氫箟浜庡墠婧愭枃浠跺栦嬌鐢ㄥ嚱鏁板簲璇ユ枃浠惰存槑瑕佷嬌鐢ㄤ簺鍑芥暟婧愭枃浠惰佸寘鍚鏂囦歡
鍏ㄥ矓鍙橀噺闈欐佸彉閲忔病鎵嬪伐鍒濆嬪寲鍒欑敱緙栬瘧鍣ㄥ垵濮嬪寲0灞閮ㄥ彉閲忓肩煡
⑤ JAVA 中的關鍵字static
static
C++的static有兩種用法:面向過程程序設計中的static和面向對象程序設計中的static。前者應用於普通變數和函數,不涉及類;後者主要說明static在類中的作用。
一、面向過程設計中的static
1、靜態全局變數
在全局變數前,加上關鍵字static,該變數就被定義成為一個靜態全局變數。我們先舉一個靜態全局變數的例子,如下:
//Example 1#include <iostream.h>void fn();static int n; //定義靜態全局變數void main(){ n=20; cout<<n<<endl; fn();}void fn(){ n++; cout<<n<<endl;}
靜態全局變數有以下特點:
該變數在全局數據區分配內存;
未經初始化的靜態全局變數會被程序自動初始化為0(自動變數的值是隨機的,除非它被顯式初始化);
靜態全局變數在聲明它的整個文件都是可見的,而在文件之外是不可見的;
靜態變數都在全局數據區分配內存,包括後面將要提到的靜態局部變數。對於一個完整的程序,在內存中的分布情況如下圖:
代碼區
全局數據區
堆區
棧區
一般程序的由new產生的動態數據存放在堆區,函數內部的自動變數存放在棧區。自動變數一般會隨著函數的退出而釋放空間,靜態數據(即使是函數內部的靜態局部變數)也存放在全局數據區。全局數據區的數據並不會因為函數的退出而釋放空間。細心的讀者可能會發現,Example 1中的代碼中將
static int n; //定義靜態全局變數
改為
int n; //定義全局變數
程序照樣正常運行。
的確,定義全局變數就可以實現變數在文件中的共享,但定義靜態全局變數還有以下好處:
靜態全局變數不能被其它文件所用;
其它文件中可以定義相同名字的變數,不會發生沖突;
您可以將上述示例代碼改為如下:
//Example 2//File1#include <iostream.h>void fn();static int n; //定義靜態全局變數void main(){ n=20; cout<<n<<endl; fn();}//File2#include <iostream.h>extern int n;void fn(){ n++; cout<<n<<endl;}
編譯並運行Example 2,您就會發現上述代碼可以分別通過編譯,但運行時出現錯誤。 試著將
static int n; //定義靜態全局變數
改為
int n; //定義全局變數
再次編譯運行程序,細心體會全局變數和靜態全局變數的區別。
2、靜態局部變數
在局部變數前,加上關鍵字static,該變數就被定義成為一個靜態局部變數。
我們先舉一個靜態局部變數的例子,如下:
//Example 3#include <iostream.h>void fn();void main(){ fn(); fn(); fn();}void fn(){ static n=10; cout<<n<<endl; n++;}
通常,在函數體內定義了一個變數,每當程序運行到該語句時都會給該局部變數分配棧內存。但隨著程序退出函數體,系統就會收回棧內存,局部變數也相應失效。
但有時候我們需要在兩次調用之間對變數的值進行保存。通常的想法是定義一個全局變數來實現。但這樣一來,變數已經不再屬於函數本身了,不再僅受函數的控制,給程序的維護帶來不便。
靜態局部變數正好可以解決這個問題。靜態局部變數保存在全局數據區,而不是保存在棧中,每次的值保持到下一次調用,直到下次賦新值。
靜態局部變數有以下特點:
該變數在全局數據區分配內存;
靜態局部變數在程序執行到該對象的聲明處時被首次初始化,即以後的函數調用不再進行初始化;
靜態局部變數一般在聲明處初始化,如果沒有顯式初始化,會被程序自動初始化為0;
它始終駐留在全局數據區,直到程序運行結束。但其作用域為局部作用域,當定義它的函數或語句塊結束時,其作用域隨之結束;
3、靜態函數
在函數的返回類型前加上static關鍵字,函數即被定義為靜態函數。靜態函數與普通函數不同,它只能在聲明它的文件當中可見,不能被其它文件使用。
靜態函數的例子:
//Example 4#include <iostream.h>static void fn();//聲明靜態函數void main(){ fn();}void fn()//定義靜態函數{ int n=10; cout<<n<<endl;}
定義靜態函數的好處:
靜態函數不能被其它文件所用;
其它文件中可以定義相同名字的函數,不會發生沖突;
二、面向對象的static關鍵字(類中的static關鍵字)
1、靜態數據成員
在類內數據成員的聲明前加上關鍵字static,該數據成員就是類內的靜態數據成員。先舉一個靜態數據成員的例子。
//Example 5#include <iostream.h>class Myclass{public: Myclass(int a,int b,int c); void GetSum();private: int a,b,c; static int Sum;//聲明靜態數據成員};int Myclass::Sum=0;//定義並初始化靜態數據成員Myclass::Myclass(int a,int b,int c){ this->a=a; this->b=b; this->c=c; Sum+=a+b+c;}void Myclass::GetSum(){ cout<<"Sum="<<Sum<<endl;}void main(){ Myclass M(1,2,3); M.GetSum(); Myclass N(4,5,6); N.GetSum(); M.GetSum();}
可以看出,靜態數據成員有以下特點:
對於非靜態數據成員,每個類對象都有自己的拷貝。而靜態數據成員被當作是類的成員。無論這個類的對象被定義了多少個,靜態數據成員在程序中也只有一份拷貝,由該類型的所有對象共享訪問。也就是說,靜態數據成員是該類的所有對象所共有的。對該類的多個對象來說,靜態數據成員只分配一次內存,供所有對象共用。所以,靜態數據成員的值對每個對象都是一樣的,它的值可以更新;
靜態數據成員存儲在全局數據區。靜態數據成員定義時要分配空間,所以不能在類聲明中定義。在Example 5中,語句int Myclass::Sum=0;是定義靜態數據成員;
靜態數據成員和普通數據成員一樣遵從public,protected,private訪問規則;
因為靜態數據成員在全局數據區分配內存,屬於本類的所有對象共享,所以,它不屬於特定的類對象,在沒有產生類對象時其作用域就可見,即在沒有產生類的實例時,我們就可以操作它;
靜態數據成員初始化與一般數據成員初始化不同。靜態數據成員初始化的格式為:
<數據類型><類名>::<靜態數據成員名>=<值>
類的靜態數據成員有兩種訪問形式:
<類對象名>.<靜態數據成員名> 或 <類類型名>::<靜態數據成員名>
如果靜態數據成員的訪問許可權允許的話(即public的成員),可在程序中,按上述格式來引用靜態數據成員 ;
靜態數據成員主要用在各個對象都有相同的某項屬性的時候。比如對於一個存款類,每個實例的利息都是相同的。所以,應該把利息設為存款類的靜態數據成員。這有兩個好處,第一,不管定義多少個存款類對象,利息數據成員都共享分配在全局數據區的內存,所以節省存儲空間。第二,一旦利息需要改變時,只要改變一次,則所有存款類對象的利息全改變過來了;
同全局變數相比,使用靜態數據成員有兩個優勢:
靜態數據成員沒有進入程序的全局名字空間,因此不存在與程序中其它全局名字沖突的可能性;
可以實現信息隱藏。靜態數據成員可以是private成員,而全局變數不能;
2、靜態成員函數
與靜態數據成員一樣,我們也可以創建一個靜態成員函數,它為類的全部服務而不是為某一個類的具體對象服務。靜態成員函數與靜態數據成員一樣,都是類的內部 實現,屬於類定義的一部分。普通的成員函數一般都隱含了一個this指針,this指針指向類的對象本身,因為普通成員函數總是具體的屬於某個類的具體對象的。通常情況下,this 是預設的。如函數fn()實際上是this->fn()。但是與普通函數相比,靜態成員函數由於不是與任何的對象相聯系,因此它不具有this指針。從這個意義上講,它無法訪問屬於類對象的非靜態數據成員,也無法訪問非靜態成員函數,它只能調用其餘的靜態成員函數。下面舉個靜態成員函數的例子。
//Example 6#include <iostream.h>class Myclass{public: Myclass(int a,int b,int c); static void GetSum();/聲明靜態成員函數private: int a,b,c; static int Sum;//聲明靜態數據成員};int Myclass::Sum=0;//定義並初始化靜態數據成員Myclass::Myclass(int a,int b,int c){ this->a=a; this->b=b; this->c=c; Sum+=a+b+c; //非靜態成員函數可以訪問靜態數據成員}void Myclass::GetSum() //靜態成員函數的實現{// cout<<a<<endl; //錯誤代碼,a是非靜態數據成員 cout<<"Sum="<<Sum<<endl;}void main(){ Myclass M(1,2,3); M.GetSum(); Myclass N(4,5,6); N.GetSum(); Myclass::GetSum();}
關於靜態成員函數,可以總結為以下幾點:
出現在類體外的函數定義不能指定關鍵字static;
靜態成員之間可以相互訪問,包括靜態成員函數訪問靜態數據成員和訪問靜態成員函數;
非靜態成員函數可以任意地訪問靜態成員函數和靜態數據成員;
靜態成員函數不能訪問非靜態成員函數和非靜態數據成員;
由於沒有this指針的額外開銷,因此靜態成員函數與類的全局函數相比速度上會有少許的增長;
調用靜態成員函數,可以用成員訪問操作符(.)和(->)為一個類的對象或指向類對象的指針調用靜態成員函數,也可以直接使用如下格式:
<類名>::<靜態成員函數名>(<參數表>)
調用類的靜態成員函數。
===============================================================================================
static靜態變數聲明符。 在聲明它的程序塊,子程序塊或函數內部有效,值保持,在整個程序期間分配存儲器空間,編譯器默認值0。
是C++中很常用的修飾符,它被用來控制變數的存儲方式和可見性。
2、為什麼要引入static?
函數內部定義的變數,在程序執行到它的定義處時,編譯器為它在棧上分配空間,大家知道,函數在棧上分配的空間在此函數執行結束時會釋放掉,這樣就產生了一個問題: 如果想將函數中此變數的值保存至下一次調用時,如何實現?最容易想到的方法是定義一個全局的變數,但定義為一個全局變數有許多缺點,最明顯的缺點是破壞了此變數的訪問范圍(使得在此函數中定義的變數,不僅僅受此函數控制)。
3、什麼時候用static?
需要一個數據對象為整個類而非某個對象服務,同時又力求不破壞類的封裝性,即要求此成員隱藏在類的內部,對外不可見。
4、static的內部機制:
靜態數據成員要在程序一開始運行時就必須存在。因為函數在程序運行中被調用,所以靜態數據成員不能在任何函數內分配空間和初始化。
這樣,它的空間分配有三個可能的地方,一是作為類的外部介面的頭文件,那裡有類聲明;二是類定義的內部實現,那裡有類的成員函數定義;三是應用程序的main()函數前的全局數據聲明和定義處。
靜態數據成員要實際地分配空間,故不能在類的聲明中定義(只能聲明數據成員)。類聲明只聲明一個類的「尺寸和規格」,並不進行實際的內存分配,所以在類聲明中寫成定義是錯誤的。它也不能在頭文件中類聲明的外部定義,因為那會造成在多個使用該類的源文件中,對其重復定義。
static被引入以告知編譯器,將變數存儲在程序的靜態存儲區而非棧上空間,靜態
數據成員按定義出現的先後順序依次初始化,注意靜態成員嵌套時,要保證所嵌套的成員已經初始化了。消除時的順序是初始化的反順序。
5、static的優勢:
可以節省內存,因為它是所有對象所公有的,因此,對多個對象來說,靜態數據成員只存儲一處,供所有對象共用。靜態數據成員的值對每個對象都是一樣,但它的值是可以更新的。只要對靜態數據成員的值更新一次,保證所有對象存取更新後的相同的值,這樣可以提高時間效率。
6、引用靜態數據成員時,採用如下格式:
<類名>::<靜態成員名>
如果靜態數據成員的訪問許可權允許的話(即public的成員),可在程序中,按上述格式
來引用靜態數據成員。
7、注意事項:
(1)類的靜態成員函數是屬於整個類而非類的對象,所以它沒有this指針,這就導致
了它僅能訪問類的靜態數據和靜態成員函數。
(2)不能將靜態成員函數定義為虛函數。
(3)由於靜態成員聲明於類中,操作於其外,所以對其取地址操作,就多少有些特殊
,變數地址是指向其數據類型的指針 ,函數地址類型是一個「nonmember函數指針」。
(4)由於靜態成員函數沒有this指針,所以就差不多等同於nonmember函數,結果就
產生了一個意想不到的好處:成為一個callback函數,使得我們得以將C++和C-based X W
indow系統結合,同時也成功的應用於線程函數身上。
(5)static並沒有增加程序的時空開銷,相反她還縮短了子類對父類靜態成員的訪問
時間,節省了子類的內存空間。
(6)靜態數據成員在<定義或說明>時前面加關鍵字static。
(7)靜態數據成員是靜態存儲的,所以必須對它進行初始化。
(8)靜態成員初始化與一般數據成員初始化不同:
初始化在類體外進行,而前面不加static,以免與一般靜態變數或對象相混淆;
初始化時不加該成員的訪問許可權控制符private,public等;
初始化時使用作用域運算符來標明它所屬類;
所以我們得出靜態數據成員初始化的格式:
<數據類型><類名>::<靜態數據成員名>=<值>
(9)為了防止父類的影響,可以在子類定義一個與父類相同的靜態變數,以屏蔽父類的影響。這里有一點需要注意:我們說靜態成員為父類和子類共享,但我們有重復定義了靜態成員,這會不會引起錯誤呢?不會,我們的編譯器採用了一種絕妙的手法:name-mangling 用以生成唯一的標志。
編輯本段static 函數
內部函數和外部函數
當一個源程序由多個源文件組成時,C語言根據函數能否被其它源文件中的函數調用,將函數分為內部函數和外部函數。
1 內部函數(又稱靜態函數)
如果在一個源文件中定義的函數,只能被本文件中的函數調用,而不能被同一程序其它文件中的函數調用,這種函數稱為內部函數。
定義一個內部函數,只需在函數類型前再加一個「static」關鍵字即可,如下所示:
static 函數類型 函數名(函數參數表)
{……}
關鍵字「static」,譯成中文就是「靜態的」,所以內部函數又稱靜態函數。但此處「static」的含義不是指存儲方式,而是指對函數的作用域僅局限於本文件。
使用內部函數的好處是:不同的人編寫不同的函數時,不用擔心自己定義的函數,是否會與其它文件中的函數同名,因為同名也沒有關系。
2 外部函數
外部函數的定義:在定義函數時,如果沒有加關鍵字「static」,或冠以關鍵字「extern」,表示此函數是外部函數:
[extern] 函數類型 函數名(函數參數表)
{……}
調用外部函數時,需要對其進行說明:
[extern] 函數類型 函數名(參數類型表)[,函數名2(參數類型表2)……];
[案例]外部函數應用。
(1)文件mainf.c
main()
{ extern void input(…),process(…),output(…);
input(…); process(…); output(…);
}
(2)文件subf1.c
……
extern void input(……) /*定義外部函數*/
{……}
(3)文件subf2.c
……
extern void process(……) /*定義外部 函數*/
{……}
(4)文件subf3.c
……
extern void output(……) /*定義外部函數*/
{……}