首先說一下記憶體的五個區:
- 棧(stack):由編譯器自動配置設定釋放,存放函數的參數值,局部變量的值(除static),其操作方式類似于資料結構中的棧。
- 堆(heap):一般由程式員配置設定釋放,若程式員不釋放,程式結束時可能由OS回收。注意它與資料結構中的堆(優先隊列)是兩回事,配置設定方式是類似于連結清單。
- 全局區(靜态區):全局變量和靜态變量的存儲是放在一塊的,初始化的全局變量和靜态變量在一塊區域,未初始化的全局變量和靜态變量在相鄰的另一區域,程式結束後由系統釋放。
- 文字常量區:常量字元串放在這裡,如char str[]="hello",程式結束後由系統釋放,差別const修飾的變量。
- 程式代碼區:存放函數體的二進制代碼。
static變量:
靜态局部變量儲存在全局資料區(靜态區),而不是儲存在棧中,每次的值保持到下一次調用,知道下次賦新值。
static成員變量:
定義必須在類定義體的外部,在類的内部隻是聲明,聲明必須加static,定義不需要。
class A
{
public:
//聲明static變量,任何聲明都不可初始化,如extern外部變量
static int a;
private:
static int b;
};
//定義static成員變量,可初始化
int A::a = 5;
//私有靜态成員變量,不能直接用類名調用或者對象調用,隻能在類内調用
int A::b = 1; //error!
static變量跟類相關,跟具體的對象無關,static變量為類的所有執行個體對象所共享,某個執行個體對象修改了該靜态成員變量,其修改值為該類所有其他執行個體對象可見。
#include<iostream>
using namespace std;
class A
{
public:
//聲明為static變量,任何聲明都不可初始化,如extern外部變量
static int a;
private:
static int b;
public:
static int getValue(){
return a;
}
};
//定義static成員變量,可初始化
int A::a = 5;
int main(int argc,char** argv)
{
A* instanceA=new(A);
A* instanceB=new(A);
instanceA->a = 1;
cout<<A::a<<endl;
cout<<instanceA->getValue()<<endl; //輸出1
cout<<instanceB->getValue()<<endl; //輸出1
return 0;
}
staic 函數:
a.cpp
#include<cstdio>
int a = 5;
void printHello()
{
printf("Hello world!\n");
}
b.cpp
#include<cstdio>
//聲明
void printHello();
int main(int argc,char** argv)
{
//聲明
extern int a;
printf("a=%d\n",a);
printHello();
return 0;
}
g++ a.cpp b.cpp -o ab.out 輸出
a=5
Hello,world!
分析:如果在a.cpp中的int a=5; 定義前面加上static修飾,再次去編譯,在b.cpp中會報未定義錯誤。類似的,在a.cpp中的void printHello()函數前面加上static修飾,再次去編譯,一樣也會報未定義錯誤。很明顯,所有未加static修飾的函數和全局變量具有全局可見性,其他的源檔案也能夠通路,如果加上static修飾,則隻能在目前源檔案中可見,對其他源檔案是不可見的。static的這一特性可以在不同的檔案中定義同名函數和同名變量,而不必擔心命名沖突。
static成員函數:
與成員變量一樣,靜态成員函數隻和類相關,跟具體的對象無關,可以通過類名來調用,當然也可以通過執行個體對象來調用。
static成員函數裡面不能通路非靜态成員變量,也不能調用非靜态成員函數。
靜态成員函數沒有this隐含指針修飾,也不能為virtual修飾。