C++static的使用

詳見: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.調用靜態成員函數,可以用成員訪問操作符(.)和(->)爲一個類的對象或指向類對象的指針調用靜態成員函數,也可以用類名::函數名調用(因爲他本來就是屬於類的,用類名調用很正常)
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章