• 类的static成员并用其实现一个单例模式


        对于特定类型的全体对象而言,有时候可能需要访问一个全局的变量。比如说统计某种类型对象已创建的数量。如果我们用全局变量会破坏数据的封装,一般的用户代码都可以修改这个全局变量,这时我们可以用类的静态成员来解决这个问题。

        静态成员和静态成员函数在使用时可以直接用类名加域运算符使用。也可以用对象.的方法(即使这样也不会传递this指针给非静态成员函数),但不推荐,因为这样容易产生歧义,实际上他们并不相关。

        static成员在类体内的仅仅是引用性声明,不允许初始化!必须在类定义体外进行定义性声明与初始化!且不能加static。。。特殊的是static const int类型的成员可以在类体内初始化,也可以不在类体外重新定义。

        static成员函数不能访问非静态成员,也不能访问非静态成员函数。但非静态成员函数能访问静态成员、静态成员函数。

    #ifndef _COUNTEDOBJECT_H_
    #define _COUNTEDOBJECT_H_
    
    class CountedObject
    {
    public:
        CountedObject();
        ~CountedObject();
    
        static int count_;
    };
    
    #endif
    CountedObject.h
    #include "CountedObject.h"
    
    int CountedObject::count_ = 0; //不能加static
    
    CountedObject::CountedObject()
    {
        ++count_;
    }
    
    CountedObject::~CountedObject()
    {
        --count_;
    }
    CountedObject.cpp
    #include "CountedObject.h"
    #include <iostream>
    using namespace std;
    
    int main()
    {
        cout << CountedObject::count_ << endl;
        CountedObject col1;
        cout << CountedObject::count_ << endl;
        CountedObject *col2 = new CountedObject;
        cout << CountedObject::count_ << endl;
        delete col2;
        cout << CountedObject::count_ << endl;
    
        return 0;
    }

        运行结果:

        如果count_是私有的,那么就需要定义一个接口来访问他。

        

    static用法总结

        1. 用于函数内部修饰变量,即函数内的静态变量。这种变量的生存期长于该函数,使得函数具有一定的“状态”。局部静态变量只在第一次进入函数时初始化。使用静态变量的函数一般是不可重入的,也不是线程安全的,比如strtok(3)。

    2. 用在文件级别(函数体之外),修饰变量或函数,表示该变量或函数只在本文件可见,其他文件看不到也访问不到该变量或函数。专业的说法叫“具有internal linkage”,区别于“extern linkage”(简言之:不暴露给别的translation unit)。

    在使用全局变量时应注意在.c文件中进行声明,千万不能在.h文件中声明(当被两个文件包含时,会导致重复声明)。

    以上是c语言中的两种用法。C++除了以上两种,还有:

    3.用于修饰类的数据成员,即所谓“静态成员”。这种数据成员的生存期大于class的对象(实例/instance)。静态数据成员是每个class有一份,普通数据成员是每个instance 有一份。

    4. 用于修饰class的成员函数,即所谓“静态成员函数”。这种成员函数只能访问静态成员和其他静态程员函数,不能访问非静态成员和非静态成员函数。

        单例模式:保证一个类只有一个实例,并提供一个全局访问点;禁止拷贝。

    #include <iostream>
    using namespace std;
    
    class Singleton
    {
    public:
        static Singleton *Getinstance()
        {
            if (instance_ != NULL)
                instance_ = new Singleton;
            return instance_;
        }
    private:
        Singleton()
        {
    
        }
        static Singleton* instance_;
    };
    
    Singleton* Singleton::instance_;
    
    int main()
    {
        Singleton* s1 = Singleton::Getinstance();
        Singleton* s2 = Singleton::Getinstance();
    
        return 0;
    }

        要保证类不被多次实例化,首先要把构造函数声明为私有的。那么又要保证类有一个实例,所以提供一个全局的接口Getinstance,他在instance_为空的时候调用构造函数,在其为非空时之间返回instance_。这样保证了有且只能有一个实例。上述代码不能保证对象不被拷贝或赋值,因此还需把拷贝构造函数和赋值运算符函数声明为私有的:

    private:
        Singleton(const Singleton& other);
        Singleton& operator=(const Singleton& );

        上述代码还有一个缺点,就是类包含动态成员,在程序结束时不会自动释放内存。可以定义一个嵌套类来释放:

    #include <iostream>
    using namespace std;
    
    class Singleton
    {
    public:
        static Singleton *Getinstance()
        {
            if (instance_ == NULL)
                instance_ = new Singleton;
            return instance_;
        }
        ~Singleton()
        {
            cout << "~Singleton" << endl;
        }
    
        class Garbo
        {
        public:
            ~Garbo()
            {
                if (instance_ != NULL)
                    delete instance_;
            }
        };
    
    private:
        Singleton(const Singleton& other);
        Singleton& operator=(const Singleton& );
        Singleton()
        {
            cout << "Singleton" << endl;
        }
        static Singleton* instance_;
        static Garbo garbo_;
    };
    
    Singleton::Garbo Singleton::garbo_;//注意声明方式
    Singleton* Singleton::instance_;
    
    int main()
    {
        Singleton* s1 = Singleton::Getinstance();
        Singleton* s2 = Singleton::Getinstance();
    
        return 0;
    }

        运行结果:

        还有一种更简单的方法:

    #include <iostream>
    using namespace std;
    
    class Singleton
    {
    public:
        static Singleton &Getinstance()
        {
            static Singleton instance_;
                return instance_;
        }
        ~Singleton()
        {
            cout << "~Singleton" << endl;
        }
    
    private:
        Singleton(const Singleton& other);
        Singleton& operator=(const Singleton& );
        Singleton()
        {
            cout << "Singleton" << endl;
        }
    };
    
    int main()
    {
        Singleton& s1 = Singleton::Getinstance();//引用不可省,否则会调用拷贝构造函数
        Singleton& s2 = Singleton::Getinstance();
    
        return 0;
    }

        运行结果同上。

  • 相关阅读:
    DataSet数据导出为Excel文档(每个DataTable为一个Sheet)
    K2 Blackpearl 4.6.8 安装步骤详解
    解决未能从程序集xxx中加载类型System.ServiceModel.Activation.HttpModule的问题
    将博客搬至CSDN
    PMS-授权中心
    如何从现有版本1.4.8升级到element UI2.0.11
    Maven私有仓库: 发布release版本报错:Return code is: 400, ReasonPhrase: Repository does not allow upd ating assets: maven-releases.
    spring boot + dubbo开发遇到过的异常
    java,javascript中的url编码
    SpringBoot favicon.ico
  • 原文地址:https://www.cnblogs.com/lulu10922/p/5820603.html
Copyright © 2020-2023  润新知