static关键字作用


1、隐藏变量

当两个文件中存在全局变量时,通过extern关键字可以引用不同文件中的变量。如果加入static关键字,全局变量的作用域在文件内,其他文件无法访问。利用这一特性可以在不同的文件中定义同名函数和同名变量,而不必担心命名冲突。static可以用作函数和变量的前缀,对于函数来讲,static的作用仅限于隐藏.

2、静态全局变量

静态全局变量具有全局作用域,如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被static关键字修饰过的变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量。

静态全局变量在静态存储区分配空间,在程序刚开始运行时就完成初始化,也是唯一的一次初始化

全局变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。

局部变量也只有局部作用域,它是自动对象(auto),它在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。

静态局部变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。

静态全局变量也具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被static关键字修饰过的变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量。

从分配内存空间看:
全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,而局部变量在栈里分配空间。

从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。

3、默认初始化为0

全局变量也具备这一属性,因为全局变量也存储在静态数据区。在静态数据区,内存中所有的字节默认值都是0x00,

最后对static的三条作用做一句话总结。首先static的最主要功能是隐藏,其次因为static变量存放在静态存储区,所以它具备持久性和默认值0. 

4、修饰普通函数

static修饰一个函数,则这个函数只能在本文件中调用,不能被同一程序其他文件调用。则其他文件可以定义相同名字的函数,不会发生冲突。

5、修饰成员变量

静态数据成员是类的成员,而不是对象的成员,在类中声明static变量或者函数时,初始化时使用作用域运算符来标明它所属类,

(1)静态数据成员可以实现多个对象之间的数据共享,它是类的所有对象的共享成员,它在内存中只占一份空间,如果改变它的值,则各对象中这个数据成员的值都被改变。 
(2)静态数据成员是静态存储的,是在程序开始运行时被分配空间,到程序结束之后才释放,只要类中指定了静态数据成员,即使不定义对象,也会为静态数据成员分配空间。非静态成员(变量和方法)属于类的对象,所以只有在类的对象产生(创建类的实例)时才会分配内存,然后通过类的对象(实例)去访问。 

(3)静态数据成员可以被初始化,但是只能在类体外进行初始化,若未对静态数据成员赋初值,则编译器会自动为其初始化为0 

     静态成员初始化与一般数据成员初始化不同:
       初始化在类体外进行,而前面不加static,以免与一般静态变量或对象相混淆;
       初始化时不加该成员的访问权限控制符private,public等;
        初始化时使用作用域运算符来标明它所属类;
        所以我们得出静态数据成员初始化的格式:
         <数据类型><类名>::<静态数据成员名>=<值>

(4)静态数据成员既可以通过对象名引用,也可以通过类名引用。

6、修饰成员函数

(1)类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致了它仅能访问类的静态数据成员和静态成员函数。

(2)不能将静态成员函数定义为虚函数:

 虚函数依靠vptr和vtable来处理。vptr是一个指针,在类的构造函数中创建生成,并且只能用this指针来访问它,因为它是类的一个成员,并且vptr指向保存虚函数地址的vtable.
   对于静态成员函数,它没有this指针,所以无法访问vptr. 这就是为何static函数不能为virtual.
   虚函数的调用关系:this -> vptr -> vtable ->virtual function
(3)由于静态成员声明于类中,操作于其外,所以对其取地址操作,就多少有些特殊,变量地址是指向其数据类型的指针,函数地址类型是一个“nonmember函数指针”。

(4)由于静态成员函数没有this指针,所以就差不多等同于nonmember函数,结果就产生了一个意想不到的好处:成为一个callback函数,使得我们得以将C++和C-based X Window系统结合,同时也成功的应用于线程函数身上。
(5)static并没有增加程序的时空开销,相反它还缩短了子类对父类静态成员的访问时间,节省了子类的内存空间。
(9)为了防止父类的影响,可以在子类定义一个与父类相同的静态变量,以屏蔽父类的影响。这里有一点需要注意:我们说静态成员为父类和子类共享,但我们又重复定义了静态成员,这会不会引起错误呢?不会,我们的编译器采用了一种绝妙的手法:name-mangling 用以生成唯一的标志

猜你喜欢

转载自blog.csdn.net/qq_22238021/article/details/80276347