C++ static詳解,類中的static用法說明
C++static詳解,類中static用法
static特點(diǎn):用來控制存儲(chǔ)方式和可見性
① 存儲(chǔ)空間:靜態(tài)存儲(chǔ)區(qū)(控制變量的存儲(chǔ)方式)
靜態(tài)變量存儲(chǔ)在靜態(tài)存儲(chǔ)區(qū)(存儲(chǔ)在靜態(tài)存儲(chǔ)區(qū)的變量,如果不顯式地對其進(jìn)行初始化,系統(tǒng)會(huì)將其初始化為0),在程序執(zhí)行期間,對應(yīng)的存儲(chǔ)空間不會(huì)釋放,一直到程序結(jié)束才會(huì)釋放。
static控制變量的存儲(chǔ)方式體現(xiàn)在局部變量上。局部變量存儲(chǔ)在動(dòng)態(tài)存儲(chǔ)區(qū),在局部變量定義前加上static,該局部變量就變成了局部靜態(tài)變量,局部靜態(tài)變量存儲(chǔ)在靜態(tài)存儲(chǔ)區(qū),即使函數(shù)調(diào)用結(jié)束,它占用的存儲(chǔ)空間也不會(huì)釋放,但其他函數(shù)不能引用該局部靜態(tài)變量。當(dāng)下一次調(diào)用該函數(shù)時(shí),不會(huì)再次對該局部靜態(tài)變量進(jìn)行初始化,它的值是上一次函數(shù)調(diào)用結(jié)束時(shí)的值。
對全局變量而言,存儲(chǔ)方式?jīng)]有什么改變,因?yàn)槿肿兞亢腿朱o態(tài)變量都存儲(chǔ)在靜態(tài)存儲(chǔ)區(qū)。
② 作用域:(控制變量、函數(shù)的可見性)
static控制變量的可見性體現(xiàn)在全局靜態(tài)變量和靜態(tài)函數(shù)上。
全局變量默認(rèn)具有外部鏈接性,作用域是整個(gè)工程。使用static關(guān)鍵字可以限制全局變量的作用域,全局靜態(tài)變量的作用域僅限本文件,它對在其他文件不可見,也就是說不能在其他文件中引用該全局靜態(tài)變量,但其他文件中可以定義和它名字相同的變量,不會(huì)發(fā)生沖突。
在函數(shù)的返回類型前加上static關(guān)鍵字,函數(shù)即被定義為靜態(tài)函數(shù)。靜態(tài)函數(shù)與普通函數(shù)的不同在于,它只能在聲明它的文件當(dāng)中可見,不能被其它文件使用,其它文件中可以定義相同名字的函數(shù),不會(huì)發(fā)生沖突。
局部靜態(tài)變量的作用域與局部變量的作用域相同,其作用域都是從定義開始到函數(shù)或程序塊結(jié)束為止。
類中的static關(guān)鍵字
在類中聲明static變量或者函數(shù)時(shí),初始化時(shí)使用作用域運(yùn)算符(::)來標(biāo)明它所屬類,靜態(tài)成員是類的成員(所有對象中共享的成員),而不是某一個(gè)對象的成員。
① 靜態(tài)數(shù)據(jù)成員
在類內(nèi)數(shù)據(jù)成員的聲明前加上關(guān)鍵字static,該數(shù)據(jù)成員就是類內(nèi)的靜態(tài)數(shù)據(jù)成員。
靜態(tài)數(shù)據(jù)成員和普通數(shù)據(jù)成員一樣遵從public,protected,private訪問規(guī)則。
對于非靜態(tài)數(shù)據(jù)成員,每個(gè)對象都有自己的拷貝。而靜態(tài)數(shù)據(jù)成員被當(dāng)作是類的成員。無論這個(gè)類的對象被定義了多少個(gè),靜態(tài)數(shù)據(jù)成員在程序中也只有一份拷貝,由該類的所有對象共享訪問。也就是說,靜態(tài)數(shù)據(jù)成員是該類的所有對象所共有的。對該類的多個(gè)對象來說,靜態(tài)數(shù)據(jù)成員只會(huì)被分配一次內(nèi)存,供所有對象共用。所以,靜態(tài)數(shù)據(jù)成員的值對每個(gè)對象都是一樣的,它的值可以更新。
因?yàn)殪o態(tài)數(shù)據(jù)成員在全局?jǐn)?shù)據(jù)區(qū)分配內(nèi)存,屬于本類的所有對象共享,所以,它不屬于特定的對象,在沒有產(chǎn)生類對象時(shí)其作用域就可見,即在沒有產(chǎn)生類的實(shí)例時(shí),我們就可以操作它。
同全局變量相比,使用靜態(tài)數(shù)據(jù)成員有兩個(gè)優(yōu)勢:
靜態(tài)數(shù)據(jù)成員沒有進(jìn)入程序的全局名字空間,因此不存在與程序中其它全局名字沖突的可能性;
可以實(shí)現(xiàn)信息隱藏。靜態(tài)數(shù)據(jù)成員可以是private成員,而全局變量不能;
② 靜態(tài)成員函數(shù)
與靜態(tài)數(shù)據(jù)成員一樣,我們也可以創(chuàng)建一個(gè)靜態(tài)成員函數(shù),它為類的全部服務(wù)而不是為某一個(gè)類的具體對象服務(wù)。靜態(tài)成員函數(shù)與靜態(tài)數(shù)據(jù)成員一樣,都是類的內(nèi)部實(shí)現(xiàn),屬于類定義的一部分。普通的成員函數(shù)一般都隱含了一個(gè)this指針,this指針指向類的對象本身,因?yàn)槠胀ǔ蓡T函數(shù)總是具體的屬于某個(gè)類的具體對象的。通常情況下,this是缺省的,如函數(shù)fun()實(shí)際上是this->fun()。但是與普通函數(shù)相比,靜態(tài)成員函數(shù)由于不與任何的對象相聯(lián)系,因此它不具有this指針。
非靜態(tài)成員函數(shù)可以任意地訪問靜態(tài)成員函數(shù)和靜態(tài)數(shù)據(jù)成員;
靜態(tài)成員函數(shù)不能訪問非靜態(tài)成員函數(shù)和非靜態(tài)數(shù)據(jù)成員;靜態(tài)成員之間可以相互訪問,包括靜態(tài)成員函數(shù)訪問靜態(tài)數(shù)據(jù)成員和訪問靜態(tài)成員函數(shù);
什么時(shí)候用static?
需要一個(gè)數(shù)據(jù)對象為整個(gè)類而非某個(gè)對象服務(wù),同時(shí)又力求不破壞類的封裝性,即要求此成員隱藏在類的內(nèi)部,對外不可見。
為什么要引入static?
函數(shù)內(nèi)部定義的變量,在程序執(zhí)行到它的定義處時(shí),編譯器為它在棧上分配空間,大家知道,函數(shù)在棧上分配的空間在此函數(shù)執(zhí)行結(jié)束時(shí)會(huì)釋放掉,這樣就產(chǎn)生了一個(gè)問題:如果想將函數(shù)中此變量的值保存至下一次調(diào)用時(shí),如何實(shí)現(xiàn)?最容易想到的方法是定義一個(gè)全局的變量,但定義為一個(gè)全局變量有許多缺點(diǎn),最明顯的缺點(diǎn)是破壞了此變量的訪問范圍(使得在此函數(shù)中定義的變量,不僅僅受此函數(shù)控制)。
c++中static總結(jié)
經(jīng)過static修飾的變量,存儲(chǔ)在內(nèi)存的全局靜態(tài)區(qū)。且被static修飾的變量只能在本模塊的所有函數(shù)引用。
內(nèi)存中的存儲(chǔ)區(qū)域如下:
- 堆區(qū):是由程序員手動(dòng)申請(new)與釋放(delete)的內(nèi)存區(qū)域。從低地址向高地址申請;內(nèi)存空間大、存儲(chǔ)地址不連續(xù),一般是鏈?zhǔn)降?;速度較慢。
- 棧區(qū):由編譯器自動(dòng)分配和釋放,主要存儲(chǔ) 函數(shù)的參數(shù)值、函數(shù)內(nèi)部的變量的值、函數(shù)調(diào)用的空間。從高地址向低地址申請;容量有限;速度較快;存儲(chǔ)地址連續(xù),會(huì)溢出。
- 代碼區(qū):又叫文本段(.text),存放著程序的機(jī)器代碼,可執(zhí)行指令就是存儲(chǔ)在這里的,這里的代碼是只讀的。
- 全局區(qū)(靜態(tài)區(qū)):全局變量和靜態(tài)變量是存儲(chǔ)在這里的。初始化的全局變量和靜態(tài)變量在一塊區(qū)域(.data),未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域(.bbs)。系統(tǒng)結(jié)束后由系統(tǒng)釋放。
- 常量區(qū):常量字符串放在這里,程序結(jié)束后,由系統(tǒng)進(jìn)行釋放。
1. 概念
static的用法主要體現(xiàn)在兩個(gè)方面:面向過程中的static和面向?qū)ο笾械膕tatic。
面向過程的static主要包括靜態(tài)全局變量、靜態(tài)局部變量和靜態(tài)函數(shù)。
面向?qū)ο蟮膕tatic主要包括靜態(tài)成員變量、靜態(tài)成員函數(shù)。
2. 面向過程的static
2.1 靜態(tài)全局變量
全局變量前添加static關(guān)鍵字,則該變量稱為靜態(tài)全局變量。
#include <iostream> #include <stdio.h> ? static int a = 10; ? void Func() { ?? ?a++; } ? int main() { ?? ?printf("a = %d\n", a);//輸出:10 ?? ?Func();//輸出:10 ?? ?printf("a = %d\n", a);//輸出:11 ? ?? ?system("pause"); ? ? return 0; }
特點(diǎn):
1)在全局?jǐn)?shù)據(jù)中的變量如果沒有顯示的初始化會(huì)自動(dòng)被程序初始化為0(這個(gè)特性非靜態(tài)全局變量也有),而在函數(shù)體內(nèi)聲明的變量如果不顯示初始化則會(huì)使一個(gè)隨機(jī)值;
2)靜態(tài)全局變量在聲明它的整個(gè)文件中都是可見的,而在文件之外是不可見的;
3)靜態(tài)全局變量在全局?jǐn)?shù)據(jù)區(qū)分配內(nèi)存;
4)其他文件中可以定義同名int型變量a,不會(huì)沖突;
如果將static去掉,具有以下特點(diǎn):
1)全局變量默認(rèn)是有外部連接性的,其作用域是整個(gè)工程,在一個(gè)文件內(nèi)定義的全局變量可以通過包含其所在頭文件或顯示調(diào)用 extern關(guān)鍵字修飾全局變量的變量名聲明來引用;
2)靜態(tài)全局變量是顯示調(diào)用static修飾的全局變量,其作用域只在聲明此變量的文件中,其他文件即使使用extern關(guān)鍵字修飾其聲明也不可使用;
2.2 靜態(tài)局部變量
局部變量前添加static關(guān)鍵字,則該變量稱為靜態(tài)局部變量。
#include <iostream> #include <stdio.h> ? void Func() { ?? ?static int a = 5; ?? ?printf("a = %d\n", a); ?? ?a++; } ? int main() { ?? ?for (int i = 0; i < 5; i++) ?? ?{ ?? ??? ?Func(); ?//打印結(jié)果:5 6 7 8 9 ?? ?} ? ?? ?system("pause"); ? ? return 0; }
通常,在一個(gè)函數(shù)作用域內(nèi)定義一個(gè)變量,每次運(yùn)行到該函數(shù)時(shí),系統(tǒng)會(huì)給局部變量分配內(nèi)存。當(dāng)函數(shù)結(jié)束時(shí),該變量的內(nèi)存會(huì)被系統(tǒng)回收至棧內(nèi)存當(dāng)中。
特點(diǎn):
1)內(nèi)存存放在程序的全局?jǐn)?shù)據(jù)區(qū)中;
2)靜態(tài)局部變量在程序執(zhí)行到該對象聲明時(shí),會(huì)被首次初始化。其后運(yùn)行到該對象的聲明時(shí),不會(huì)再次初始化,這也是為什么上面程序測試函數(shù)每次輸出的值都是遞增的原因(只會(huì)被初始化一次);
3)如果靜態(tài)局部變量沒有被顯式初始化,則其值會(huì)自動(dòng)被系統(tǒng)初始化為0;
4)局部靜態(tài)變量不能被其作用域之外的其他模塊調(diào)用,其調(diào)用范圍僅限于聲明該變量的函數(shù)作用域當(dāng)中;
2.3 靜態(tài)函數(shù)
函數(shù)返回類型前添加static關(guān)鍵字,則該變量稱為靜態(tài)函數(shù)。
#include <iostream> #include <stdio.h> ? static void Func() { ?? ?printf("This is a static function\n"); } ? int main() { ?? ?Func();? ?? ? ?? ?system("pause"); ? ? return 0; }
特點(diǎn):
1)作用域只在聲明它的文件當(dāng)中,不能被其他文件引用,其他文件可以定義同名的全局函數(shù);
2)其他文件想要調(diào)用本文件的靜態(tài)函數(shù),需要顯示的調(diào)用extern關(guān)鍵字修飾其聲明;
3. 面向?qū)ο笾械膕tatic
3.1 靜態(tài)成員變量
#include <iostream> #include <stdio.h> using namespace std; ? class Test { public: ?? ?Test(int a, int b, int c) :? ?? ??? ?m_a(a), ?? ??? ?m_b(b), ?? ??? ?m_c(c) ?? ?{ ?? ??? ?m = a + b + c; ?? ?} ? ?? ?void Show() ?? ?{ ?? ??? ?cout << "m = " << m << endl; ?? ?} ? private: ?? ?int m_a, m_b, m_c; ?? ?static int m; }; ? int Test::m = 0; //初始化靜態(tài)數(shù)據(jù)成員 ? int main() { ?? ?Test ClassA(1, 1, 1); ?? ?ClassA.Show(); ?//輸出: 3 ?? ?Test ClassB(3, 3, 3); ?? ?ClassB.Show(); //輸出: 9 ?? ?ClassA.Show(); //輸出: 9 ? ?? ?system("pause"); ?? ?return 0; }
特點(diǎn):
1)靜態(tài)數(shù)據(jù)成員的服務(wù)對象并非是單個(gè)類實(shí)例化的對象,而是所有類實(shí)例化的對象(這點(diǎn)可以用于設(shè)計(jì)模式中的單例模式實(shí)現(xiàn));
2)靜態(tài)數(shù)據(jù)成員必須顯式的初始化分配內(nèi)存,在其包含類沒有任何實(shí)例化之前已經(jīng)有內(nèi)存分配;
3)靜態(tài)數(shù)據(jù)成員與其他成員一樣,遵從public,protected,private的訪問規(guī)則;
4)靜態(tài)數(shù)據(jù)成員內(nèi)存存儲(chǔ)在全局?jǐn)?shù)據(jù)區(qū),只隨著進(jìn)程的消亡而消亡;
優(yōu)勢:
1)靜態(tài)數(shù)據(jù)成員不進(jìn)入程序全局命名空間,不會(huì)與其他全局名稱的同名同類型變量沖突;
2)靜態(tài)數(shù)據(jù)成員可以實(shí)現(xiàn)C++的封裝特性,由于其遵守類的訪問權(quán)限規(guī)則,所以相比全局變量更加靈活;
3.2 靜態(tài)成員函數(shù)
類的成員函數(shù)返回類型之前添加static,此成員函數(shù)為靜態(tài)成員函數(shù)。
#include <iostream> #include <stdio.h> using namespace std; ? class Test { public: ?? ?Test(int a, int b, int c) :? ?? ??? ?m_a(a), ?? ??? ?m_b(b), ?? ??? ?m_c(c) ?? ?{ ?? ??? ?m = a + b + c; ?? ?} ? ?? ?static void Show() ?? ?{ ?? ??? ?cout << "m = " << m << endl; ?? ?} ? private: ?? ?int m_a, m_b, m_c; ?? ?static int m; }; ? int Test::m = 0; //初始化靜態(tài)數(shù)據(jù)成員 ? int main() { ?? ?Test ClassA(1, 1, 1); ?? ?ClassA.Show(); ?? ?Test ClassB(3, 3, 3); ?? ?ClassB.Show(); ?? ?ClassA.Show(); ? ? ? Test::Show(); //輸出: 9 ? ?? ?system("pause");? ?? ?return 0; }
特點(diǎn):
1)靜態(tài)成員函數(shù)比普通成員函數(shù)多了一種調(diào)用方式;
2)在沒有實(shí)例化的類對象的條件下可以調(diào)用類的靜態(tài)成員函數(shù);
3)靜態(tài)成員函數(shù)中沒有隱含的this指針,所以靜態(tài)成員函數(shù)不可以操作類中的非靜態(tài)成員(由于第二條可知,類的非靜態(tài)成員是在類實(shí)例化后存在的,而類的成員函數(shù)可以在類沒有實(shí)例化的時(shí)候調(diào)用,故不能操作類的非靜態(tài)成員);
4. 小結(jié)
1)靜態(tài)數(shù)據(jù)成員都是靜態(tài)存儲(chǔ)的,所以必須在main函數(shù)之前顯示的對其進(jìn)行初始化;
2)不能再頭文件中聲明靜態(tài)全局變量,原因是可能是產(chǎn)生了多個(gè)同名的靜態(tài)數(shù)據(jù);
3)不能將靜態(tài)成員函數(shù)定義為虛函數(shù);
4)靜態(tài)成員函數(shù)沒有this指針;
5)static縮短了子類對父類靜態(tài)成員訪問的時(shí)間,相對來說節(jié)省了內(nèi)存空間;
6)如果不想在子類中操作父類的靜態(tài)成員,則可以在子類中定義一個(gè)同名的static成員。這樣既可覆蓋父類中的靜態(tài)成員,并且根據(jù)C++的多態(tài)性變量命名規(guī)則,這樣做是安全的;
7)靜態(tài)成員聲明在類中,操作在其外部,所以對其取地址操作就跟取普通成員的操作略有不同。靜態(tài)變量地址是指向其數(shù)據(jù)類型的指針,函數(shù)地址則是一個(gè)類型為nonmember的函數(shù)指針;
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
C語言關(guān)于注釋的知識點(diǎn)總結(jié)
在本篇文章里小編給大家分享的是關(guān)于C語言關(guān)于注釋的知識點(diǎn)總結(jié),需要的朋友們可以參考學(xué)習(xí)下。2020-02-02c++入門必學(xué)算法之快速冪思想及實(shí)現(xiàn)
快速冪相較于普通的冪,具有占用空間少,效率更高等優(yōu)點(diǎn),全面碾壓普通的冪,下面這篇文章主要給大家介紹了關(guān)于c++入門必學(xué)算法之快速冪思想及實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2022-11-11