c++中的靜態類型 static


static根據上下文語意有兩種含義,一種是在類和結構體內,另一種時類在結構體外。

類外的static在鏈接階段是局部的,它只對它的編譯單元(.obj)可見,而類內的static表示這個變量將在類內與所有實例共享

Static.cpp

static int s_Variable=5;

main.cpp

#include<iostream>

int s_Variable=10;

int main()
{
    std::cout<<s_Variable<<std::endl;
    std::cin.get();
}

程序的運行結果是打印10,如果將Static.cpp中的static去掉,直接變成int聲明變量s_Variable,那么在鏈接時會報錯,因為s_Variable已經在另一個編譯單元中被定義了,兩個全局變量的名字不能一樣,改正方法是使用引用

Static.cpp

int s_Variable=5;

main.cpp

#include<iostream>

extern int s_Variable;

int main()
{
    std::cout<<s_Variable<<std::endl;
    std::cin.get();
}

extern的意思是在另外的編譯單元中尋找定義,也叫外部鏈接,此時運行可以看到打印結果是5。加上static有些類似於在類中聲明私有類型成員,其他的編譯單元(.obj)不能訪問s_Variable,函數也是一樣。

Static.cpp

void function()
{}

main.cpp

#include<iostream>

int function()
{}

int main()
{
    std::cin.get();
}

此時編譯會發生錯誤,因為function被重復定義,如果將Static.cpp中的function前面加上static,那么鏈接將不會出錯。

在頭文件中使用靜態變量也是同樣的道理,頭文件相當於在引用頭文件的位置將頭文件的內容復制粘貼,因此頭文件中使用static定義的靜態變量即使在兩個不同的cpp文件中被調用,也不會引起重復定義,因為它相當於在兩個cpp文件中各自建立一個靜態變量,互不干擾。

因此盡量讓全局變量和函數變成靜態類型,除非要在別的cpp文件中調用它

 

static在類和結構內代表什么

表示類內所有同名變量都代表一個實體,如果這個屍體的值發生了改變,那么類中所有的這個實體都同樣會改變。

#include<iostream>

struct Entity{
    int x,y;
    void Print()
    {
        std::cout<<x<<","<<y<<std::endl;
    }
};

int main()
{
    Entity e;
    e.x=2;
    e.y=3;
    Entity e1={5,8};
    e.Print();
    e1.Print();
    std::cin.get();
}

打印結果是2,3   5,8  

#include<iostream>

struct Entity{
    static int x,y;
    void Print()
    {
        std::cout<<x<<","<<y<<std::endl;
    }
};

int Entity::x;
int Entity::y;

int main()
{
    Entity e;
    e.x=2;
    e.y=3;
    Entity e1;
    e1.x=5;
    e1.y=8;
    e.Print();
    e1.Print();
    std::cin.get();
}

此時的打印結果是兩個5,8,需要注意的是靜態變量無法訪問非靜態變量,如果代碼做如下修改,那么靜態函數Print將無法訪問非靜態的變量x和y

#include<iostream>

struct Entity{
    int x,y;
    static void Print()
    {
        std::cout<<x<<","<<y<<std::endl;
    }
};

int main()
{
    Entity e;
    e.x=2;
    e.y=3;
    Entity e1;
    e1.x=5;
    e1.y=8;

    Entity::Print();
    std::cin.get();
}

使用訪問命名空間的方法來訪問類/結構體中的靜態成員是因為靜態類型是唯一的,無需通過新建類/結構體來實現訪問。如果做以下修改,可以正常運行

#include<iostream>

struct Entity{
    int x,y;
    static void Print()
    {
        std::cout<<x<<","<<y<<std::endl;
    }
};

static void Print(Entity e)
{
    std::cout<<e.x<<","<<e.y<<std::endl;
}

int main()
{
    Entity e;
    e.x=2;
    e.y=3;
    Entity e1;
    e1.x=5;
    e1.y=8;

    Print(e);
    std::cin.get();
}

 

本地作用域中(local scope)的靜態變量

需要掌握的變量的生命周期(變量在被刪除之前在內存中存儲多久)和作用域(在哪里可以訪問到這個變量)

局部靜態變量允許我們定義一個生命周期是整個程序的變量,但是他的作用域被限制在當前函數中,其實也不一定是函數,可以在任何作用域中聲明靜態變量,函數中的靜態變量和類中的靜態變量其實沒有很大的區別,他們的生命周期是一樣的,唯一區別是類中的靜態變量可以被類內的任何變量訪問,在函數作用域中聲明的靜態變量,對於函數來說是局部的,就像類的靜態變量對於類來說也是局部的。如果在函數中聲明一個靜態變量,那么在第一次調用函數時,這個靜態變量被創建,后續再次調用此函數時將不會在創建這個變量。

#include<iostream>

void func()
{
    int i=0;
    i++;
    std::cout<<i<<std::endl;
}

int main()
{
    func();
    func();
    func();
    std::cin.get();
}

此函數的輸出結果是三個1,如果將int i=0改為靜態變量,那么結果將輸出1,2,3

#include<iostream>

void func()
{
    static int i=0;
    i++;
    std::cout<<i<<std::endl;
}

int main()
{
    func();
    func();
    func();
    std::cin.get();
}

將i設在函數外面作為全局變量也是一樣的結果,但是當i作為全局變量時,就意味着我在任何地方都可以調用它,所以會有一些意外的發生。

#include<iostream>

static int i=0;

void func()
{
    i++;
    std::cout<<i<<std::endl;
}

int main()
{
    func();
    i=10;
    func();
    func();
    std::cin.get();
}

此時輸出結果是1,11,12,如果不想讓程序出現這種效果,此時可以將i變成局部靜態變量

同樣,局部靜態變量可以簡化代碼

#include<iostream>

class Singleton{
private:
    static Singleton* s_Instance;
public:
    static Singleton& get() {return s_Instance;}
    void Hello() {}
};

Singleton *Singleton::s_Instance=NULL;

int main()
{
    Singleton::Get().Hello();
    std::cin.get();
}

簡化如下

#include<iostream>

class Singleton{
public:
    static Singleton& get() 
    {
        static Singleton instance;
        return instance;
    }
    void Hello() {}
};


int main()
{
    Singleton::Get().Hello();
    std::cin.get();
}

如果Singleton instance前面沒有static,因為Singleton是在堆棧上建立的,在運行到結束花括號時被銷毀,函數結束,在返回引用時這將會是個嚴重的錯誤,如果將表示引用的“&”去掉將不會有錯,加上了static將會大大延長了instance的生命周期,每次調用get()的時候后面的調用都會返回到第一次構造的Singleton實例。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM