【C++】静态成员与单例模式

来源:互联网 发布:mac safari视频下载 编辑:程序博客网 时间:2024/04/28 14:39

什么是静态成员

静态成员变量、静态成员函数、静态类

在一个类中,往往需要那么一个变量需要被各个对象共享,例如银行中的活期存款利率,如果需要一个变量去统计某个类中存在的对象个数,那么这个变量也是每个对象都共享了。这个变量可以是个全局变量,但如果定义成全局变量,就会影响类的封装性,因为我们可以在普通的代码中就可以轻松的去修改它。那么这时候就可以在类中声明一个静态成员变量变量。这样不仅能有效防止用户意外的去修改了这么一个变量,更能突出类的自洽性。

静态成员并不依赖于对象,属于类而非对象的

静态成员变量不包含在对象实例中,具有进程级的生命周期。(静态成员存放于全局区,程序运行前就已经存在)

静态成员函数没有this指针,也没有常属性。(this指向的是正在构造的对象 或者 已经存在的对象,静态成员属于类,不属于对象更不依赖于对象,所以不存在this指针)

静态成员依然受类作用域和访问控制限定符的约束。

所以我们可以把静态成员变量看做一个受作用域和访控属性影响的全局变量。


静态成员变量的使用

静态成员变量的定义和初始化,只能在类的外部而不能在构造函数中进行。

语法: 对象.静态成员 / 类名::静态成员


/*   静态成员*/#include <iostream>using namespace std;class Account{public://修改利率static int setRate(double const& rate){if (rate <= 0 || rate >= 0.005)return -1;s_rate = rate;return 0;}//查看利率static double getRate(void) {return s_rate;}//构造函数Account(string name, int passwd, double balance = 0) :m_id(1000 + s_size++), m_name(name), m_passwd(passwd), m_balance(balance){/*构造函数*/}//打印用户信息void print(void) const{cout << "帐号:" << m_id << endl;cout << "名字:" << m_name << endl;cout << "存款:" << m_balance << endl;cout << "当前利率:" << s_rate << endl;}/*以下省略存款、取款等功能 */private://不允许拷贝帐号,拷贝构造函数私有化Account(Account& that) {}; static double s_rate; //利率static size_t s_size; //帐号个数int    m_id;      //卡号string m_name;      //用户名int    m_passwd;      //密码double m_balance;     //存款};//以下静态成员变量必须在类外定义、初始化double Account::s_rate = 0.003; //利率初始化size_t Account::s_size = 0;//帐号个数初始化int main(void){cout << "查看当前利率:" << Account::getRate() << endl;Account Jack("JACK", 123456, 1000);Account Tom("TOM", 123456, 2000);Account::setRate(0.004); //等价于Jack.setRate() 或 Tom.setRate()Jack.print();Tom.print();return 0;}

运行结果:


由此可见,类Account中的静态成员变量s_rate和s_size是共享与每个对象之中,且不依赖与对象而存在。


单例模式

当我们设计一个类的时候,只允许存在唯一的对象实例的时候,就需要用到单例模式,单例模式一般分别有饿汉模式和懒汉模式。如网站的计数器、数据库应用的连接池、多线程应用的线程池等等都用到了单例模式。虽然可以通过定义一个全局变量(对象)貌似也可以实现,功能也差不多,但是全句变量(对象)的定义不受控制,防君子不防小人。


什么是单例模式

单例模式只允许存在一个对象,且在类外部是禁止创建实例的,所以构造函数必须都私有化。

在类的定义中,声明一个该类的静态成员变量,这个变量是类唯一的实例,由该类自己维护。

在一般情况下,为了体现出类良好的封装性,一般把这个静态成员变量私有化,然后提供一个静态成员函数,通过该静态成员函数可以访问到该唯一的实例


饿汉模式

优点:该模式中,单例对象在程序运行前就存在,所以不需要考虑会被多个线程在某种情况下、同一时刻中创建多个对象。

缺点:该单例模式中的唯一对象无论是否被使用,都会被创建,降低空间利用率。


/*   单例模式 - 饿汉模式*/#include <iostream>using namespace std;class Singleton{public://静态成员函数,返回静态成员s_instance的引用static Singleton& getInstance(void){return s_instance;}private:/*不允许用户创建和拷贝对象,构造函数私有化*/Singleton(int x = 100) : m_data(x) {}Singleton(Singleton& sigleton) {}static Singleton s_instance;int m_data;};//静态成员变量必须在类外定义、初始化Singleton Singleton::s_instance(200); int main(void){Singleton& s1 = Singleton::getInstance();Singleton& s2 = Singleton::getInstance();Singleton& s3 = Singleton::getInstance();cout << "s1 = " << &s1 << endl;;cout << "s2 = " << &s2 << endl;;cout << "s3 = " << &s3 << endl;;return 0;}

运行结果:


3对象的地址都相同,证明了返回的是同一个变量的引用。


懒汉模式

优点:用则创建,不用不创建,什么时候用什么时候创建

缺点:首次访问的时动态创建单例对象,在多线程应用中会存在线程不安全的问题。

/*   单例模式 - 懒汉模式*/#include <iostream>using namespace std;class Singleton{public:static Singleton& getInstance(void){if (NULL == s_instance){//首次创建单例对象的时候需要考虑线程安全,需要加入互斥锁pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;pthread_mutex_lock(&mutex);if (NULL == s_instance){s_instance = new Singleton(200);}pthread_mutex_unlock(&mutex);}return *s_instance;}private:Singleton(int data = 100) : m_data(data) {}Singleton(Singleton const&) {}static Singleton* s_instance;int m_data;};//初始化Singleton中的静态成员s_instanceSingleton* Singleton::s_instance = NULL;int main(void){Singleton &s1 = Singleton::getInstance();Singleton &s2 = Singleton::getInstance();Singleton &s3 = Singleton::getInstance();cout << &s1 << endl;cout << &s2 << endl;cout << &s3 << endl;return 0;}

使用静态成员函数需要注意的地方:

由于静态成员不依赖于任何对象、且属于类不属于对象,所以静态成员函数只能访问静态成员变量或调用静态成员函数。

非静态成员函数由于参数中隐藏着this指针,所以既可以访问静态成员变量或调用静态成员函数,也可以访问非静态成员变量或调用非静态成员函数。







0 0
原创粉丝点击