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实例。

posted @ 2020-04-09 20:35  Wangtn  阅读(3313)  评论(0编辑  收藏  举报