标签:
静态数据成员要在程序一开始运行时就必须存在。因为函数在程序运行中被调用,所以静态数据成员不能在任何函数内分配空间和初始化。
这样,它的空间分配有三个可能的地方,一是作为类的外部接口的头文件,那里有类声明;二是类定义的内部实现,那里有类的成员函数定义;三是应用程序的main()函数前的全局数据声明和定义处。
静态数据成员要实际地分配空间,故不能在类的声明中定义(只能声明数据成员)。类声明只声明一个类的“尺寸和规格”,并不进行实际的内存分配,所以在类声 明中写成定义是错误的。它也不能在头文件中类声明的外部定义,因为那会造成在多个使用该类的源文件中,对其重复定义。
static被引入以告知编译器,将变量存储在程序的静态存储区而非栈上空间,静态数据成员按定义出现的先后顺序依次初始化,注意静态成员嵌套时,要保证所嵌套的成员已经初始化了。消除时的顺序是初始化的反顺序。
1、扩展生存期
这一点主要是针对普通局部变量和static局部变量来说的。声明为static的局部变量的生存期不再是当前作用域,而是整个程序的生存期。
在程序中,常用内存类型主要有堆、栈和静态存储区。要理解static局部变量就必须首先理解这三种内存类型。
在C/C++中, 局部变量按照存储形式可分为三种auto, static, register
static是按照程序的生命周期来分配释放变量的,而不是变 量自己的生命周期. 如果在main前设置断点,然后查看static变量,已经被初始化,也就是说static在执行main函数前已经被初始化。也就是在程序初始化时被分配。
静态存储区:由在编译时由编译器分配,由系统释放,其中存放的是全局变量、static变量和常量.
区别:
1) 堆是由低地址向高地址扩展,栈是由高地址向低地址扩展。
2) 堆是不连续的空间,栈是连续的空间。
3) 在申请空间后,栈的分配要比堆的快。对于堆,先遍历存放空闲存储地址的链表、修改链表、再进行分配;对于栈,只要剩下的可用空间足够,就可分配到,如果不够,那么就会报告栈溢出。
4) 栈的生命期最短,到函数调用结束时;静态存储区的生命期最长,到程序结束时;堆中的生命期是到被我们手动释放时(如果整个过程中都不手动释放,那就到程序结束时)。
--------------
把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。
如果作为static局部变量在函数内定义,它的生存期为整个源程序,但是其作用域仍与自动变量相同,只能在定义该变量的函数内使用该变量。退出该函数后, 尽管该变量还继续存在,但不能使用它。
static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝.
2、限制作用域
这一点相对于普通全局变量和static全局变量来说的。
对于全局变量而言,不论是普通全局 变量还是static全局变量,其存储区都是静态存储区,因此在内存分配上没有什么区别。
区 别在于:
1) 普通的全局变量和函数,其作用域为整个程序或项目,外部文件(其它cpp文件)可以通过extern关键字访问该变量和函数。一般不提倡这种用法,如果要在多个cpp文件间共享数据,应该将数据声明为extern类型。
在头文件里声明为extern:
extern int g_value; // 注意,不要初始化值!
然后在其中任何一个包含该头文件的cpp中初始化(一次)就好:
int g_value = 0; // 初始化一样不要extern修饰,因为extern也是声明性关键字;
然后所有包含该头文件的cpp文件都可以用g_value这个名字访问相同的一个变量;
2) static全局变量和函数,其作用域为当前cpp文件,其它的cpp文件不能访问该变量和函数。如果有两个cpp文件声明了同名的全局静态变量,那么他们实际上是独立的两个变量。
static函数的好处是不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。
头文件中的static变量
如果在一个头文件中声明:
static int g_vaule = 0;
那么会为每个包含该头文件的cpp都创建一个全局变量,但他们都是独立的;所以也不建议这样的写法,一样不明确需要怎样使用这个变量,因为只是创建了一组同名而不同作用域的变量。
3、static的第三个作用是默认初始化为0,其实全局变量也具备这一属性,因为全局变量也存储在静态数据区。
最后对static的三条作用做一句话总结。首先static的最主要功能是隐藏,其次因为static变量存放在静态存储区,所以它具备持久性和默认值0.
4、C++中static
这是C++对static关键字的重用。主要指静态数据成员/成员函数。
表示属于一个类而不是属于此类的任何特定对象的变量和函数. 这是与普通成员函数的最大区别, 也是其应用所在, 比如在对某一个类的对象进行计数时, 计数生成多少个类的实例, 就可以用到静态数据成员. 在这里面, static既不是限定作用域的, 也不是扩展生存期的作用, 而是指示变量/函数在此类中的唯一性. 这也是”属于一个类而不是属于此类的任何特定对象的变量和函数”的含义. 因为它是对整个类来说是唯一的, 因此不可能属于某一个实例对象的. (针对静态数据成员而言, 成员函数不管是否是static, 在内存中只有一个副本, 普通成员函数调用时, 需要传入this指针, static成员函数调用时, 没有this指针. )
一、类的静态成员函数是属于整个类而非类的对象,所以它没有this指针,这就导致了它仅能访问类的静态数据和静态成员函数。• 静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义;
• 静态数据成员和普通数据成员一样遵从public,protected,private访问规则;
同全局变量相比,使用静态数据成员有两个优势:
1. 静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性;
2. 可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能;
a.静态数据成员被 类 的所有对象所共享,包括该类派生类的对象。即派生类对象与基类对象共享基类的静态数据成员。举例如下:
1 class base 2 { 3 public : 4 static int _num;//声明 5 }; 6 int base::_num=0;//静态数据成员的真正定义 7 class derived:public base 8 { 9 }; 10 main() 11 { 12 base a; 13 derived b; 14 a._num++; 15 cout<<"base class static data number _num is"<<a._num<<endl; 16 b._num++; 17 cout<<"derived class static data number _num is"<<b._num<<endl; 18 } 19 // 结果为1,2;可见派生类与基类共用一个静态数据成员。
b.静态数据成员可以成为成员函数的可选参数,而普通数据成员则不可以。举例如下:
1 class base 2 { 3 public : 4 static int _staticVar; 5 int _var; 6 void foo1(int i=_staticVar);//正确,_staticVar为静态数据成员 7 void foo2(int i=_var);//错误,_var为普通数据成员 8 };
c.★静态数据成员的类型可以是所属类的类型,而普通数据成员则不可以。普通数据成员的只能声明为 所属类类型的 指针或引用。举例如下:
1 class base 2 { 3 public : 4 static base _object1;//正确,静态数据成员 5 base _object2;//错误 6 base *pObject;//正确,指针 7 base &mObject;//正确,引用 8 };
标签:
原文地址:http://www.cnblogs.com/balingybj/p/4535627.html