static

来源:互联网 发布:js阻止超链接跳转 编辑:程序博客网 时间:2024/06/05 00:54

    static----意思是,静态的。

    不得不说static这个关键字在C++里面比较复杂,用法也是很奇特,至少在很多时候你不能单纯的把用法和它这个“静态的”意思结合起来。

    static至少有4种惯常用法,静态局部变量,静态全局变量,静态数据成员,静态函数成员。头痛,真的有点头痛,为了把这四种用法分清楚我算是豁出去了。忍不住要问自己倒腾这个东西干啥?难道仅仅好奇心?也许好奇心确实是一个重要的成分,不搞清楚真的不想罢休,好歹算一个编程爱好者吧,这都搞不清楚怎么好意思。


一,静态局部变量

    不妨先来看一个例子

#include <iostream>using namespace std;void display(){int num=0;cout << num << endl;num++;}int main(){display();display();display();return 0;}
    输出结果如下:


    这应该是我们预期的结果,没有任何疑问,也不需要怀疑什么。

    下面我们在display()函数中给局部变量num加入关键字static,程序如下:

#include <iostream>using namespace std;void display(){static int num=0;cout << num << endl;num++;}int main(){display();display();display();return 0;}

    输出结果如下:


    不得不承认这个结果不是我们预想的,至少在没接触过static关键之之前,是想不到这样的结果的。

    我们称num是局部变量是因为num的作用域仅仅只是在display()这个子函数中,但是一旦在局部把它变成static类型之后感觉num似乎变成了一个全局变量,因为它的值在执行完子函数之后被保留了下来。再次联想“静态的”这个意义,我猜想当初创立这个static关键字的人可能是出于这样一种目的----创立者眼中的静态是指变量开辟存储空间之后的过程是静态的不变的。基于这样一个想法,我觉得静态局部变量表达的是这样一个意思----对于局部变量,加上static之后,在程序编译的过程中给它分配存储空间,之后无论程序怎样跑,初始化的过程不会再次执行。为了验证这种想法,我采用设置断点逐条执行的方式跑程序发现,第6行的这个初始化过程从来都没有执行过,强哥在书上告诉读者这条语句是在编译的时候执行的,现在看来这句话确实不假。


二,静态全局变量

    顾名思义,是将一个全局变量加上一个static关键字修饰,一种常见的形式如下:

file1.cppstatic int a=0;int main(){    ...    ...}
    这里无法给出例子运行结果来验证什么,逼格有点高,因为这涉及到大型程序,源文件有很多个的情形,只能做一个简单介绍。

    先不要看上面,现在我们假定file1.cpp中定义了一个全局变量int a=0。如果我们想要在file2.cpp中引用file1.cpp中的变量a的话,一个惯用方式就是在file2.cpp文件中对a进行extern修饰如下:

file2.cppextern int a;......
    假如file1.cpp中采用上面的static int a=0的话,那么file2.cpp将无法引用file1.cpp中的变量a,即便同名也不再是同一个东西。

    由此来看,静态全局变量的起的是一个变量隔离的作用,防止工程中不同源文件中全局变量名称相同而互相非法引用。“静态的”在这种状况下,将不能从字面上去理解。

三,静态数据成员

    来看在C++的类中,一个数据被static修饰的情况。

    截止到目前为止,我们对类的认识是----不管我们如何定义一个类,类里面定义了多少种数据类型,在没有定义对象的时候,这个类里面是没有数据的,它仅仅只是一种结构而已,并没有实实在在的数据。开门见山,static的引入,使得类拥有了自己的数据,这个数据不被对象专有,而是类提供给各个不同对象共享的一个数据。

    请看实例:

#include <iostream>using namespace std;class Box{public:static int num;int length;int width;int height;Box(int, int,int);};Box::Box(int l, int w,int h)  //静态数据成员的初始化方式{length = l;width = w;height = h;num++;}int Box::num = 0;int main(){Box a(10,10,10);cout << a.num << endl;  //通过对象调用numBox b(20,20,20);cout << b.num << endl;Box c(30,30,30);cout << c.num << endl;cout << Box::num << endl;  //通过类调用numreturn 0;}
    输出结果如下:


    第6行,定义了静态数据成员num;

    第17行,做一个标志,每次构造完对象之后让num加1,用来统计对象的个数;

    第19行,很惊讶于这样一种初始化数据的方式,通过类直接调用num,并初始化为0;

    第24,26,28行,通过对象去调用静态数据成员num,调用成功;

    第29行,通过类调用num,调用成功;

    综上,我们发现在类里面定义的静态数据成员非常强大,它告诉我们----类中的静态数据成员不再是伴随着对象产生才产生的数据,而是属于类本身,在类定义完成之后就已经产生。我们可以直接通过类去初始化静态数据成员,直接通过类去调用静态数据成员。这表明静态数据成语已经完全脱离了普通意义上的类的某一个数据的范畴。

    

四,静态函数成员

    很明显,我们即将要面对类中的一个函数,函数被static修饰的状况。

    首先声明,静态函数成员跟静态数据成员有一样的权限,它不属于对象,而是属于类;静态函数成员没有this指针;静态函数成员只能访问静态数据成员;

    请看实例:

#include <iostream>using namespace std;class Box{public:static int num;static int GetNum();int length;int width;int height;Box(int, int,int);};Box::Box(int l, int w,int h)  {length = l;width = w;height = h;num++;}int Box::GetNum(){return num;}int Box::num = 0;int main(){Box a(10,10,10);cout << Box::GetNum()<< endl;  Box b(20,20,20);cout << Box::GetNum() << endl;Box c(30,30,30);cout << Box::GetNum() << endl;  return 0;}

    输出结果如下:


    关于声明里面提到的几点,都可以逐一在这个程序里面验证。

    至于静态函数成员的调用方式,我在这个程序里面采用的是主流的方式,Box::GetNum(),实际上也可以跟静态数据成员一样采用对象调用的方式a.GetNum(),只是不建议这样做,因为这如何能体现是静态函数属于类这样一个意义呢?

    静态函数成员没有this指针指向它,为什么?仔细想一想有才怪,因为已经说明了它不属于对象,既然连对象都没有,何来this?

    静态函数成员不能访问非静态数据成员,不信可以试试,这是编译器的语法规定。


小结

    static确实比较坑,反正写到这里,我也是要醉了。不过该总结还是得总结一下,对于static不要扣字面意思,实际上按照以上的四种用法,它的意义可以大致归结为如下:

“静态的”,“独立的”,“公共的”。

0 0
原创粉丝点击