詳見:https://blog.csdn.net/chenyijun/article/details/81938287
static的使用主要爲兩部分:不涉及類的static和涉及類的static
一、C/C++的內存分佈
1.棧區: 由編譯器自動分配釋放,像局部變量,函數參數,都是在棧區。會隨着作用於退出而釋放空間。
2.堆區:程序員分配並釋放的區域,像malloc(c),new(c++)
3.全局數據區(靜態區):全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。程序結束釋放。
4.代碼區
二、不涉及類的static的使用
不涉及類的static的使用在C語言中就已經在使用了,在C++中同樣可以使用。
主要又分爲三種用途,從作用域和生存期兩個方面進行分析:
1.靜態局部變量:
在函數內部修飾局部變量,變量的生存期到程序結束。
作用域:函數體內部, 生存期:整個程序運行期間
靜態局部變量的特點(括號內是局部變量的對比):
(1)該變量在全局數據區分配內存(局部變量在棧區分配內存);
(2)靜態局部變量在程序執行到該對象的聲明處時被首次初始化,即以後的函數調用不再進行初始化(局部變量每次函數調用都會被初始化);
(3)靜態局部變量一般在聲明處初始化,如果沒有顯式初始化,會被程序自動初始化爲0(局部變量不會被初始化);
(4)它始終駐留在全局數據區,直到程序運行結束。但其作用域爲局部作用域,也就是不能在函數體外面使用它(局部變量在棧區,在函數結束後立即釋放內存);
2.靜態全局變量:
定義在函數體外,用於修飾全局變量,表示該變量只在本文件可見。
作用域:該文件內部, 生存期:整個程序運行期間
//static_test.cpp
int b = 1007;
//test_C++.cpp
extern int b;
int main()
{
cout << b << endl;
std::cout << "Hello World!\n";
}
在不 #include "static_test.cpp"的情況下,可以通過extern 來獲取全局變量,但是不能通過extern 獲取static變量。
這裏若是對b聲明爲static那麼就不可以使用。
靜態全局變量的特點:
靜態全局變量不能被其它文件所用(全局變量可以);
其它文件中可以定義相同名字的變量,不會發生衝突(自然了,因爲static隔離了文件,其它文件使用相同的名字的變量,也跟它沒關係了);
3.靜態函數:
其它文件中的可以定義相同的名字的函數,不會發生衝突
作用域:該文件內部, 生存期:整個程序運行期間
可以使用exter來獲取其他文件中的函數。
靜態函數的特點:
1.靜態函數不能被其它文件所用;
2.其它文件中可以定義相同名字的函數,不會發生衝突;
三、涉及類的static的使用
涉及類的static的使用是在C++中額外增加的。
1.靜態數據成員:
用於修飾 class 的數據成員,即所謂“靜態成員”。這種數據成員的生存期大於 class 的對象(實體 instance)。靜態數據成員是每個 class 有一份,普通數據成員是每個 instance 有一份,因此靜態數據成員也叫做類變量,而普通數據成員也叫做實例變量。
2、靜態成員函數:
用於修飾 class 的成員函數。靜態函數屬於類的,不屬於某一個具體的對象。訪問方式,可以通過對像調用,也可以用類名::函數名進行訪問。
#include <iostream>
using namespace std;
class CRectangle
{
public:
CRectangle(int w, int h)
{
this->m_nWidth = w;
this->m_nHeght = h;
m_sSum += (this->m_nWidth * this->m_nHeght);
m_nSum += (this->m_nWidth * this->m_nHeght);
}
void GetSum()
{
cout << "m_sSum = " << m_sSum << endl;
cout << "m_nSum = " << m_nSum << endl;
}
static void StaticGetSum()
{
cout << "m_sSum = " << m_sSum << endl;
//cout << "m_nSum = " << m_nSum << endl;//error: invalid use of member 'm_nSum' in static member function
}
private:
int m_nWidth;
int m_nHeght;
int m_nSum;
static int m_sSum;
};
int CRectangle::m_sSum = 0;//初始化
int main()
{
cout << "sizeof(CRectangle) = " << sizeof(CRectangle) << endl;
CRectangle *rect1 = new CRectangle(3, 4);
rect1->GetSum();
rect1->StaticGetSum();
cout << "sizeof(rect1) = " << sizeof(*rect1) << endl;
CRectangle *rect2 = new CRectangle(6, 9);
rect2->GetSum();
rect2->StaticGetSum();//通過對像訪問
cout << "sizeof(rect2) = " << sizeof(*rect2) << endl;
//CRectangle::GetSum();//error: call to non-static member function without an object argument
CRectangle::StaticGetSum();//通過類名訪問
cout << "Hello World!" << endl;
return 0;
對於非靜態數據成員,每個類對象(實例)都有自己的拷貝。而靜態數據成員被當作是類的成員,由該類型的所有對象共享訪問,對該類的多個對象來說,靜態數據成員只分配一次內存。
靜態數據成員存儲在全局數據區。靜態數據成員初始化時要分配空間,所以不能在類聲明中初始化。
也就是說,你每new一個CRectangle,並不會爲static int s_sSum的構建一份內存拷貝,它是不管你new了多少CRectangle的實例,因爲它只與類CRectangle掛鉤,而跟你每一個CRectangle的對象沒關係。
靜態成員函數的特點
1.靜態成員之間可以相互訪問,包括靜態成員函數訪問靜態數據成員和訪問靜態成員函數;
2.非靜態成員函數可以任意地訪問靜態成員函數和靜態數據成員;
3.靜態成員函數不能訪問非靜態成員函數和非靜態數據成員;
4.調用靜態成員函數,可以用成員訪問操作符(.)和(->)爲一個類的對象或指向類對象的指針調用靜態成員函數,也可以用類名::函數名調用(因爲他本來就是屬於類的,用類名調用很正常)