static成员
对于特定类型的全体对象而言,有时候可能需要访问一个全局的变量。比如说统计某种类型对象已创建的数量。如果我们用全局变量会破坏数据的封装,一般的用户代码都可以修改这个全局变量,这时我们可以用类的静态成员来解决这个问题。非static数据成员存在于类类型的每个对象中,static数据成员独立该类的任意对象存在,它是与类关联的对象,不与类对象关联。
static成员优点:
1.static成员的名字是在类的作用域中,因此可以避免与其他类成员或全局对象名字冲突;
2.可以实施封装,static成员是可以私有的,而全局对象不可以;
3.阅读程序容易看出static成员与某个类相关联,这种可见性可以清晰地反映程序员地意图。
static成员需要在类定义体外进行初始化与定义,整形static成员可以在类定义体中初始化,不需要在类定义体外进行定义。
使用static成员实现类的个数统计:
CountedObject.h:
#pragma once
class CountedObject
{
public:CountedObject();~CountedObject();static int GetCount();
private:static int count_;//静态成员的引用性说明
};
CountedObject.cpp:
#include "CountedObject.h"int CountedObject::count_ = 0;//静态成员的定义性说明CountedObject::CountedObject()
{++count_;
}CountedObject::~CountedObject()
{--count_;
}int CountedObject::GetCount()
{return count_;
}
main.cpp:
#include <iostream>
using namespace std;
#include"CountedObject.h"int main()
{cout << CountedObject::GetCount() << endl;CountedObject co1;cout << CountedObject::GetCount() << endl;CountedObject* co2 = new CountedObject;cout << CountedObject::GetCount() << endl;delete co2;cout << CountedObject::GetCount() << endl;return 0;
}
static成员函数
static成员函数没有this指针,非静态成员函数可以访问静态成员,静态成员函数不可以访问非静态成员。
#include <iostream>
using namespace std;class Date
{
public:Date(int year) :year_(year){}static bool IsLeapYear(int year){return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);}bool IsLeapYear(){return (year_ % 4 == 0 && year_ % 100 != 0) || (year_ % 400 == 0);}
private:int year_;
};
int main()
{Date d(2012);cout << d.IsLeapYear()<<endl;cout << Date::IsLeapYear(2010) << endl;//不需要新建一个对象return 0;
}
四种对象作用域与生存期
栈对象:隐含调用构造函数(程序中没有显示调用)
堆对象:隐含调用构造函数(程序中没有显示调用)
全局对象、静态全局对象:全局对象的构造先于main函数,已初始化的全局变量或静态全局对象存储于.data段中,未初始化的全局变量或静态全局对象存储于.bss段中。
静态局部对象:已初始化静态局部对象存储于.data段中,未初始化的静态局部对象存储于.bss段中。
#include <iostream>
using namespace std;class Test
{
public:Test(int n) :n_(n){cout << "Test" << n << "..." << endl;}~Test(){cout << "~Test" << n_ << "..." << endl;}
private:int n_;
};int n;//未初始化的全局变量,初始值为0,n存储于.bss段中(block started by symbol)
int n2 = 100;//已初始化的全局变量,初始值为100,n2存储于.data段中
Test g(100);
static Test s(200);int main()
{cout << "Entering main ..." << endl;Test t(10);//栈上创建的对象,在生存期结束的时候自动释放{Test t(20);}{Test* t3 = new Test(30);//堆对象,要显示释放 作用域与生存期不等同//delete t3;}{static int n3;//n3存储于.bss中(编译期初始化)static int n4 = 100;//n4存储于.data段中(编译期初始化)static Test t4(40);//t4对象运行期初始化,存储于.data段}cout << "Exiting main ..." << endl;return 0;
}
输出如下:
static用法总结
1.用于函数内部修饰变量,即函数内的静态变量这种变量的生存期长于该函数,使得函数具有一定的“状态”。使用静态变量的函数一般是不可重入的,也不是线程安全的,比如strtok(3)。
2.用在文件级别(函数体之外),修饰变量或函数,表示该变量或函数只在本文件可见,其他文件看不到也访问不到该变量或函数。专业的说法叫“具有internal linkage”(简言之:不暴露给别的translation unit) 。
3.用于修饰类的数据成员,即所谓“静态成员”。这种数据成员的生存期大于class的对象(实例linstance) 。静态数据成员是每个class有一份,普通数据成员是每个instance有一份。
4.用于修饰class的成员函数,即所谓“静态成员函数”。这种成员函数只能访问静态成员和其他静态程员函数,不能访问非静态成员和非静态成员函数。
static与单例模式
保证一个类只有一个实例,并提供一个全局访问点,禁止拷贝。
使用嵌套类实现单例模式:
#include <iostream>
using namespace std;class Singleton
{
public:static Singleton* GetInstance(){if (instance_ == NULL){instance_ = new Singleton;}return instance_;}//static void free()//{// if (instance_ != NULL)// {// delete instance_;// }//}class Garbo{public:~Garbo(){if (Singleton::instance_ != NULL){delete instance_;}}};
private:Singleton(const Singleton& other);//拷贝构造函数声明为私有 禁止拷贝Singleton& operator=(const Singleton& other);//=运算符声明为私有 禁止拷贝Singleton(){cout << "Singleton..." << endl;//只调用了一次说明只创建了一个对象}~Singleton(){cout << "~Singleton..." << endl;}static Singleton* instance_;static Garbo garbo_;//利用对象的确定性析构
};Singleton* Singleton::instance_;//定义性说明
Singleton::Garbo Singleton::garbo_;//定义性说明int main()
{//Singleton s1;//Singleton s2;Singleton* s1 = Singleton::GetInstance();Singleton* s2 = Singleton::GetInstance();//Singleton::free();return 0;
}
使用局部静态对象实现单例模式:
#include <iostream>
using namespace std;class Singleton
{
public:static Singleton& GetInstance(){static Singleton instance;//局部静态对象return instance;}private:Singleton(const Singleton& other);//拷贝构造函数声明为私有 禁止拷贝Singleton& operator=(const Singleton& other);//=运算符声明为私有 禁止拷贝Singleton(){cout << "Singleton..." << endl;//只调用了一次说明只创建了一个对象}~Singleton(){cout << "~Singleton..." << endl;}static Singleton* instance_;
};Singleton* Singleton::instance_;//定义性说明int main()
{//Singleton s1;//Singleton s2;Singleton& s1 = Singleton::GetInstance();Singleton& s2 = Singleton::GetInstance();//Singleton::free();return 0;
}
const成员函数
const成员函数不会修改对象的状态,const成员函数只能访问数据成员的值,而不能修改它。
const对象
如果把一个对象指定为const,就是告诉编译器不要修改它,const对象不能调用非const成员函数。
mutable
用mutable修饰的数据成员即使在const对象或const成员函数中都可以被修改。比如记录某个变量的输出次数,变量不变,但输出次数要加一,此时就可以用mutable修饰输出次数。
#include <iostream>
using namespace std;class Test
{
public:Test(int x) :x_(x),outputTimes_(0){}int GetX() const {cout << "const GetX ..." << endl;return x_;}int GetX()//可以构成重载{cout << "GetX ..." << endl;return x_;}void Output() const{cout << "x=" << x_ << endl;outputTimes_++;}int GexOutputTimes() const{return outputTimes_;}
private:int x_;mutable int outputTimes_;
};int main()
{const Test t(10);t.GetX();Test t2(20);t2.GetX();t.Output();t.Output();cout << t.GexOutputTimes() << endl;return 0;
}