【C++】static详解
- static的作用
1.隐藏
当我们编译多个文件时,所有未加static前缀的全局变量和函数都具有全局可见性,其他的源文件也能访问。如,我们有源文件source1.cpp定义了一个全局变量i和函数Func
1 //source1.cpp
2 int i = 0;
3
4 void Func()
5 {
6 printf("Hello World\n");
7 }
如果在另一个文件main.cpp中是可以引用i和Func的。然而,如果一个文件要使用在其他源文件定义的变量或函数,一定要在此文件件中包含相应变量或函数的声明。其中变量一定要用extern声明,函数的声明加不加extern没有影响。如下所示:
1 //source1.cpp
2 extern int i; //变量i的声明
3 void Func(); //函数的声明
4
5 int main()
6 {
7 printf("%d\n", i); //使用变量i
8 Func(); //使用函数Func()
9
10 return 0;
11 }
如果加上static前缀,就不能像上面的程序一样被其他程序使用。
1 static int i = 0;
2
3 static void Func()
4 {
5 printf("Hello World\n");
6 }
2. static的第二个作用是默认初始化为0,包括未初始化的全局变量与局部静态变量。其实,未初始化的全局变量也具备这一属性,因为未初始化的全局变量与未初始化的静态变量时存储在同一块区域内(BSS段)
3. static的第三个作用是保持局部变量内容的持久。
函数内自动变量,当调用时就存在,退出函数时就消失,但静态局部变量虽然在函数内定义,但静态局部变量始终存在着,也就是说它的声明期为整个源程序,其特点是只进行一次初始化且拒具有’记忆性‘。
静态局部变量的生存期虽然为为整个源程序,但其作用域仍然与局部变量相同,即只能在定义该变量的函数内使用该变量。退出函数后,尽管该变量还继续存在,但不能继续使用它。
- 类中static的作用
静态数据成员:
C++重用了static这个关键字,并赋予了它与前面不同的含义:表示属于一个类而不是属于此类对象的任何特定对象的变量和函数。
通常,非static数据成员存在于类类型的每个对象中。不管该类产生多少个对象,静态成员变量永远只有一个实例,而且在没有对象实例的情况下已经存在。不像普通的数据成员,static数据成员独立于该类的任意对象而存在;每个static数据成员是与类关联的对象,并不与该类的对象相关联。也就是说当某个类的实例修改了该静态数据成员变变量,其修改值为该类的其他所有实例所见。
数据成员与普通和普通数据成员一样遵从public、protected、private访问规则。
可以通过作用域操作符从类直接调用static成员,或者通过对象、引用或指向该类类型对象的指针间接调用。
类的数据成员也存储在全局(静态)存储区。静态数据成员定义时要分配空间,所以不能在类声明中定义。
static数据成员可以声明为任意类型,可以是常量、引用、数组、类类型,等等。
static数据成员必须在类定义体的外部定义(正好一次),不像普通数据成员,static成员不是通过类构造函数初始化,而是应该在定义时初始化。
这个规则的一个例外是,只要初始化是一个常量表达式,整形const static数据成员就可以在类的定义体中进行初始化(不是定义)。然而,const static数据成员必须在类的定义体之外进行定义。
保证对象正好定义一次的最好办法,就是将static数据成员的定义放在包含类的非内联成员函数定义的文件中。
double Account::interestRate = initRate();
像使用任意的类成员一样,在类定义体外部引用类的static成员时,必须指定成员在哪个类中定义的。然而,static关键字只能用于类定义体内部的声明中,定义不能标示为static。
类的静态成员即可以被类的静态方法访问,也可以被非静态方法访问。
static成员函数:
静态成员函数与静态数据成员一样,都是类的内部实现,属于类定义的一部分,它为类服务而不是为某一个类的具体对象服务。
因为普通成员函数总是具体的属于某个类的具体对象,所以普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身。
但与普通成员函数相比,静态成员函数由于不与任何的对象相关联,因此它不具有this指针。因而它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数与访问静态数据成员。
因为static成员不是任何对象的组成部分,所以static成员函数不能被声明为const。也不能被声明为虚函数、volatile。
静态成员函数不需要必须经由类对象调用,也可以像静态数据成员一样使用类名、指向类对象的指针或引用调用:
1 class A { 2 public: 3 static void Func() { 4 cout<<"Hello World"<<endl; 5 } 6 7 static int i; 8 }; 9 10 int A::i = 9; 11 12 int main() 13 { 14 A a; 15 A* pa = &a; 16 A &ra = a; 17 18 A::Func(); //使用类型调用静态成员函数 19 a.Func(); //使用对象调用静态成员函数 20 pa->Func(); //使用对象指针调用静态成员函数 21 ra.Func(); //使用对象引用调用静态成员函数 22 23 cout<<A::i<<endl; //使用类型调用静态数据成员 24 cout<<a.i<<endl; //使用对象调用静态数据成员 25 cout<<pa->i<<endl;//使用对象指针调用静态数据成员 26 cout<<ra.i<<endl; //使用对象引用调用静态成员数据 27 28 return 0; 29 }
- 参考资料
1. 《C++ Primer 第四版》
2. 《王道程序员求职宝典》
3. 《深度探索C++对象模型》
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。