C/C++---static函式,static成員函式,static變數,static成員變數 再來理一理
首先說一下記憶體的五個區:
- 棧(stack):由編譯器自動分配釋放,存放函式的引數值,區域性變數的值(除static),其操作方式類似於資料結構中的棧。
- 堆(heap):一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由OS回收。注意它與資料結構中的堆(優先佇列)是兩回事,分配方式倒是類似於連結串列。
- 全域性區(靜態區):全域性變數和靜態變數的儲存是放在一塊的,初始化的全域性變數和靜態變數在一塊區域,未初始化的全域性變數和未初始化的靜態變數在相鄰的另一塊區域(BSS),程式結束後由系統釋放。
- 文字常量區:常量字串就是放在這裡的,如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;
跟類相關的,跟具體的類的物件無關,為所有例項所共享,某個類的例項修改了該靜態成員變數,其修改值為該類的其它所有例項所見。
#include <iostream>
using namespace std;
class A
{
public:
// 宣告static變數,任何宣告都不可初始化,如extern外部變數
static int a;
private :
static int b;
public:
static int getAValue()
{
return this.a;
}
};
// 定義static成員變數,可初始化
int A::a = 5;
// 私有靜態成員變數,不能直接用類名呼叫或者物件呼叫,只能在類內呼叫
int A::b = 1;
int main(int argc, char *argv[])
{
// new 兩個個例項(物件)
A * instanceA = new A();
A * instanceB = new A();
// 改變值,均輸出1
instanceA->a = 1;
cout << A::a << endl;
cout << instanceA->getAValue() << endl;
cout << instanceB->getAValue() << endl;
return 0;
}
static 函式:
【a.cpp】
#include <stdio.h>
int a = 5;
void printHello()
{
printf("hello world");
}
【b.cpp】
#include <stdio.h>
// 宣告
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.exe
【輸出】
a = 5
hello world
【分析】
如果在a.cpp中的int a = 5;定義前面加上static修飾,那麼再次去編譯,就會b.cpp報未定義錯誤。
如果在a.cpp中的void printHello()函式前加static修飾,再次去編譯,一樣會報未定義錯誤。
很明顯,所有未加static修飾的函式和全域性變數具有全域性可見性,其他的原始檔也能夠訪問。static修飾函式和變數這一特性可以在不同的檔案中定義同名函式和同名變數,而不必擔心命名衝突。
static可以用作函式和變數的字首,對於函式來講,static的作用僅限於隱藏。這有點類似於C++中的名字空間。
static 成員函式:
同樣的和成員變數一樣,跟類相關的,跟具體的類的物件無關,可以通過類名來呼叫。
static成員函式裡面不能訪問非靜態成員變數,也不能呼叫非靜態成員函式。
#include <iostream>
using namespace std;
class A
{
public:
void printStr()
{
printf("hello world");
}
static void print()
{
// 錯誤,靜態成員函式不能呼叫非靜態成員函式
printStr();
}
};
int main(int argc, char *argv[])
{
return 0;
}
靜態成員函式沒有this隱含指標修飾,存在一種情況,用const修飾類的成員函式(寫在函式的最後,不是前面,前面是返回值為常量),表示該函式不能修改該類的狀態,如不能在改函式裡修改成員變數(除去mutable修飾的外),因為該函式存在一個隱式的this*,const修飾後為const this*,但是當static修飾成員函式的時候是沒有this指標的,所以不能同時用static和const修飾同一個成員函式,不過可以修飾同一個成員變數。
靜態成員函式不能為virtual修飾。