C++中static關鍵字
首先說一下之前對static的認識吧。
之前就知道static是靜態的關鍵字,可以作用於變數、函式、類成員。並且static修飾的變臉為去全域性資料區。
最近為了複習,準備校招又對static進行了複習,上網查了些資料。經過一段的思考後又有不少的收穫,所以還是要不斷的學習呀。下面就接下網上搜到的,說一說static的用法的。
首先我們要有一個這個瞭解,static變數位於全域性資料區(全域性變臉也在全域性資料區),也就是說static變數的“生命週期”是整個程式,但是static變數的訪問許可權沒有發生改變。
1、static區域性變數 VS 普通區域性變數
在函式內部的static區域性變數在函式被第一次呼叫時初始化一次,下次在呼叫這個函式時不會重新為變數分配記憶體進行初始化,仍然使用的上一次建立的變數。出了函式作用域,static區域性變數沒有被銷燬(因為它在全域性資料區)。但是不能在函式作用域之外訪問(因為它是一個區域性變數)。
普通的區域性變數是存放在棧區的,過了作用域就會被銷燬掉。
程式碼:
結果:#include<iostream> #include<string> using namespace std; void foo(int b) { static int a = 3; cout << "a = " << a << "; b = " << b; a += b; cout << "; a += b後:" << a << endl; } int main() { foo(2);//第一次呼叫foo foo(1);//第二次呼叫foo,使用上一次建立的變數a return 0; }
通過結果我們可以看出來第一次呼叫foo時,為區域性static變數a申請記憶體,並初始化為3,然後執行a+=2,後a=5;第二次呼叫foo時,之前a的記憶體沒有銷燬掉(因為a存放在全域性資料區),執行了a+=1後變為6.
那麼我們總結一下,靜態區域性變數的特點(括號內為note:2,也就是區域性變數的對比):
(1)該變數在全域性資料區分配記憶體(區域性變數在棧區分配記憶體);
(2)靜態區域性變數在程式執行到該物件的宣告處時被首次初始化,即以後的函式呼叫不再進行初始化(區域性變數每次函式呼叫都會被初始化);
(3)靜態區域性變數一般在宣告處初始化,如果沒有顯式初始化,會被程式自動初始化為0(區域性變數不會被初始化);
(4)它始終駐留在全域性資料區,直到程式執行結束。但其作用域為區域性作用域,也就是不能在函式體外面使用它(區域性變數在棧區,在函式結束後立即釋放記憶體);
2、在某個檔案中的static全域性變數 VS 普通全域性變數
在檔案開始的地方定義的變數為全域性變數,全域性static變數。
static int i = 1; //全域性static變數
int j = 1; //全域性變數
全域性變數和全域性static變數的區別在於,全域性static不能跨檔案使用,而全域性變數可以跨檔案使用。
case1如下,在a.c檔案中有一個全域性變數,在檔案b.c中使用extern關鍵字就可以使用這個全域性變量了。
//檔案 a.c 中
int n = 15; //全域性變數
//檔案 b.c中
#include <stdio.h>
extern int n;
void fn()
{
n++;
printf("after: %d\n",n);
}
void main()
{
printf("before: %d\n",n);
fn();
}
輸出為:before: 15after: 16
case2:在檔案a.c中有一個全域性static變數,在檔案b.c中使用extern關鍵字,但仍然不能使用這個全域性static變數。
//檔案 a.c
static int n = 15; //全域性static變數
//檔案 b.c
#include <stdio.h>
extern int n;
void fn()
{
n++;
printf("after: %d\n",n);
}
void main()
{
printf("before: %d\n",n);
fn();
}
此時,會出現undeference to "n"的錯誤。全域性static使用extern跨檔案使用。
3、某個檔案內的static函式 VS 普通函式
這個類似於全域性變數和全域性static變數。static函式不能跨檔案使用。
檔案a.c中的static函式,不能使用extern在b.c檔案中使用;
a.c中的普通函式,可以使用extern在b.c中使用;
4、static成員變數 VS 普通成員變數
類中的static成員變數不屬於類的某個特定的instance,而是出於整個class,被類的所有物件共享。無論建立多少個物件,在記憶體中只有一份(位於全域性資料區)。
而類的普通成員變數是屬於某個instance的,建立多少個物件,就會有多少個記憶體來存放這個變數(位於棧上)。普通成員變數,屬於某個instance。
類名::變數名;
5、static成員函式 VS static普通函式
static成員函式與static成員變數類似,屬於類,而不會屬於類的某一個特定例項。static成員函式沒有this指標。
普通成員函式,在函式形參的第一個位置隱藏了一個&obj,相當於是將這個函式與obj物件繫結在一起,this指標。普通成員函式屬於類的某一個例項。
靜態成員函式有特點
1.靜態成員之間可以相互訪問,包括靜態成員函式訪問靜態資料成員和訪問靜態成員函式;
2.非靜態成員函式可以任意地訪問靜態成員函式和靜態資料成員;
3.靜態成員函式不能訪問非靜態成員函式和非靜態資料成員;
4.呼叫靜態成員函式,可以用成員訪問操作符(.)和(->)為一個類的物件或指向類物件的指標呼叫靜態成員函式,也可以用類名::函式名呼叫(因為他本來就是屬於類的,用類名呼叫很正常)
類名::函式名(實參);