zoukankan      html  css  js  c++  java
  • 静态成员变量

    独一无二
                                              ----静态成员变量
    作者:HolyFire
    我们学习C++的时候知道静态变量的特性,他不是临时变量,在编译期间就已经产成。用一个例子就能说明问题。
    #include <iostream>
    using namespace std;
    class A{
    public:
            A(){ cout << "Can you see me Now!" << endl; }
            ~A(){ cout << "I'm Go Away!" << endl; }
    };
    void TestStatic( void )
    {
            static A a;
    }
    void main()
    {
            cout << "Program Start!" << endl;
            TestStatic();
            TestStatic();
            TestStatic();
            cout << "Program End!" << endl;
    }
    结果是:
    Program Start!
    Can you see me Now!
    Program End!
    I'm Go Away!
    A a只被定义了一次,而且析构是在主程序退出以后才进行的。这说明了什么呢,A a在void TestStatic( void )是同一个实例,他存在于整个程序但是只有在void TestStatic( void )中能访问他。
    不相信?那我们来试试看。
    #include <iostream>
    using namespace std;
    class A{
    private:
            int count;
    public:
            A():count(0){ cout << "Can you see me Now!" << endl; }
            ~A(){ cout << "I'm Go Away!" << endl; }
            void Inc(){ count++; }
            int Count(){ return count; }
    };
    void TestStatic( void )
    {
            static A a;
            a.Inc();
            cout << "count's value is : " << a.Count() << endl;
    }
    void main()
    {
            cout << "Program Start!" << endl;
            TestStatic();
            TestStatic();
            TestStatic();
            cout << "Program End!" << endl;
    }
    结果是:
    Program Start!
    Can you see me Now!
    count's value is : 1   //初始化count为0,Inc导致count自加值应该为1
    count's value is : 2   //没有初始化,Inc导致count自加值应该为2
    count's value is : 3   //没有初始化,Inc导致count自加值应该为3
    Program End!
    I'm Go Away!
    事实说明了一切,那么他是如何实现的呢,C++编译器里,他被创建在一个内存区域里,这块区域不是堆也不是栈,编译器在编译阶段就将他们记住,并为他们做好分配工作,如此一来就可以实现这个特性。
    看起来他的作用有些象全局变量,但是我们知道,使用全局变量会整加模块的耦合性,降低代码的通用性,所以静态成员变量的出现为我们编程带来的灵活性。
    如何将这个小东西用在我们的面向对象编程中呢。他扮演一个什么样的角色呢,这正是我要说的。
    我们知道,类的成员变量表示了一个类的属性,对应着对象的物质特性,他们在类的某个实例创建的时候创建,消亡的时候消亡。但是上面说到,静态变量在编译期间就已经存在了,也就是并不随着实例创建的时候创建,消亡的时候消亡。是这样吗。看事实说话。
    #include <iostream>
    using namespace std;
    class A{
    public:
            A() { cout << "A is On!" << endl; }
            ~A() { cout << "A is OFF!" << endl; }
    };
    class B{
    public:
            B() { cout << "B is On!" << endl; }
            ~B() { cout << "B is OFF!" << endl; }
    private:
            static A a;
    };
    A B::a;
    void main()
    {
            cout << "Program Start!" << endl;
            B b1,b2,b3;
            cout << "Program End!" << endl;
    }
    结果是:
    A is On! //瞧我又说中了,主程序还没有运行,构造函数就开始工作了,这时B的实例还没有登场
    Program Start!
    B is On! //b1创建了,但是b1.a并没有创建
    B is On!
    B is On!
    Program End!
    B is OFF! //B的实例销毁了,但是成员变量a没有销毁
    B is OFF!
    B is OFF!
    A is OFF!  //看吧,这才是A的析构函数
    注意一个约定:
    A B::a;
    静态成员变量的初始化一定要在主函数外面,而且静态成员变量一定要初始化。
    事实上B::a并不属于B,将他作为B的成员只是为了确定访问的权限
    private:
            static A a;
    因为这样设定以后只有B才能访问B::a,当然设计的时候要考虑清楚,如果a与B并没有关系,那么这样的设计就没有什么实际的意义。
    那么如何设计才能运用这个特性呢。
    我们来举个例子。
    我们有时候想知道类的实例有几个,也就是被实例化了几次。比如
    class A;
    A a1,a2,a3;
    那么就应该被实例化了3次。能知道这个信息应该很不错。如果用一个全局变量,那么要考虑的问题很多,全局变量会被人任意修改,全局变量定义在那里以及全局变量初始化在那里也会带来困惑,全局变量会不会跟别的全局变量重名等等。
    既然静态变量可以实现一些全局变量的功能,何不牛刀小试,看看效果如何。首先静态成员变量只有一个,而且不是类的真实属性,实际上只有一个变量,不会增加类的负担;第二可以给他加上访问限制,只要不是public那么就不能随意修改。既然好处多多,那么就开工。
    #include <iostream>
    using namespace std;
    class A{
    public:
           A(){ count++; }; //当产生一个实例的时候计数器加一
        ~A(){ count--; } //当销毁一个实例的时候计数器减一
           int GetInstanceCount(){ return count; }
    private:
           static int count;
    };
    int A::count = 0;
    void main()
    {
           cout << "Program Start! " << endl << endl;
           A a1,a2,a3;
           {
                  A a4,a5,*pa;
                  cout << "Now, Have a1 ,a2 ,a3 , a4 ,a5 Instances!" << endl;
                  cout << "Number of class A's Instance is : " << a1.GetInstanceCount() << endl << endl;
                  pa = new A;
                  cout << "Now Creat a class A's Instance!" << endl;
                  cout << "Number of class A's Instance is : " << a2.GetInstanceCount() << endl << endl;
                  delete pa;
           }
           cout << "While class's Instances a4 , a5 , pa destroy!" << endl;
           cout << "Only a1 , a2 , a3 Left , is the Count of Instance is 3 ?" << endl;
           cout << "Number of class A's Instance is : " << a3.GetInstanceCount() << endl << endl ;
    }
    结果是:
    Program Start!
    Now, Have a1 ,a2 ,a3 , a4 ,a5 Instances! //有a1 ,a2 ,a3 ,a4 ,a5五个实例
    Number of class A's Instance is : 5       //没错,正是五个
    Now Creat a class A's Instance!        //在堆里创建了一个,使用pa得到他的引用
    Number of class A's Instance is : 6      //跟想的一样,数目增加了
    While class's Instances a4 , a5 , pa destroy! //在堆里释放一个,栈里释放2个
    Only a1 , a2 , a3 Left , is the Count of Instance is 3 ? //6 ?C 1 ?C2 当然等于3啦
    Number of class A's Instance is : 3 我说的没错吧。
    因为在构造函数里操作的是同一个变量,所以才能得到正确的结果。这个技术在很多方面得到应用,比如,互斥信号,象动态连接库一样的引用计数器等等。
    这里要记住的是,类的静态成员变量实际上只有一个,它不随着类的实例的创建/销毁而增加/减少。它不是类的真正成员,并不是类的一部分。
     
    http://blog.csdn.net/adcxf/article/details/2106555
  • 相关阅读:
    将model注册进单例中,每次用的时候从单例里面取
    构建ASP.NET MVC4&JQuery&AJax&JSon示例
    ajax用法
    MVC 后台向前台传值,同一Controller下Action之间的传值,Controller与Controller之间的传值
    mvc5入门指南
    在EF中做数据索引
    json to Object
    ajax请求后返回的时间转换格式
    Target JRE version (1.8.0_101) does not match project JDK version (unknown), will use sources from JDK: 1.8
    Idea 配置启动JDK___在windows中使用Intellij Idea时选择自定义的64位JVM
  • 原文地址:https://www.cnblogs.com/findumars/p/5356039.html
Copyright © 2011-2022 走看看