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

    静态成员和静态成员函数在使用时可以直接用类名加域运算符使用。也可以用对象.的方法(即使这样也不会传递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;
}

    运行结果同上。

posted on 2016-08-30 09:33  pan.panda  阅读(519)  评论(0编辑  收藏  举报