对于特定类型的全体对象而言,有时候可能需要访问一个全局的变量。比如说统计某种类型对象已创建的数量。如果我们用全局变量会破坏数据的封装,一般的用户代码都可以修改这个全局变量,这时我们可以用类的静态成员来解决这个问题。
静态成员和静态成员函数在使用时可以直接用类名加域运算符使用。也可以用对象.的方法(即使这样也不会传递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_ = ; //不能加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 ;
}
运行结果:
如果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 ;
}
要保证类不被多次实例化,首先要把构造函数声明为私有的。那么又要保证类有一个实例,所以提供一个全局的接口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 ;
}
运行结果:
还有一种更简单的方法:
#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 ;
}
运行结果同上。