静态成员
静态成员变量
- 语法
class 类名{
public:
private:
static 数据类型 变量名;//静态成员变量声明
};
数据类型 类名::变量名 = 初值;//定义和初始化
- 对于
普通的成员变量
变量属于对象,对于静态成员变量
变量不属于对象,类中的静态成员变量可以直接通过类名 + 静态成员变量名
直接访问,相当于共享资源 普通成员变量
在构造对象时定义和初始化,而静态成员变量
需要在类的外部单独定义和初始化,而const
修饰的带有常属性的静态成员变量需要在声明的同时进行初始化静态成员变量
和全局变量
类似,被存放在全局区
(数据区/BSS区),可以把静态成员变量
理解为被限制在类中使用的全局成员变量
- 静态成员变量的使形式
类名::静态成员变量;
对象.静态成员变量;
静态成员函数
- 静态成员函数语法
class 类名 {
//静态成员函数的声明
static 返回值类型 函数名(形参表){
/*函数体*/
}
};
- 静态成员函数没有this指针,也没有const属性,可以把静态成员函数理解为被限制在类中使用的全局函数
- 静态成员函数只能访问类中的静态成员,而非静态成员函数既可以访问静态成员也可以访问非静态成员
- 静态成员函数的使用形式
类名::静态成员函数(形参表);
//如果没有参数,要保留()
对象.静态成员函数(实参表);
单例模式
- 概念
要求一个类值允许实例化唯一的一个对象,并且提供其访问方法 - 实现思路
- 禁止在类的外部创建对象:私有构造函数以及拷贝构造函数,禁止生成默认的拷贝构造
- 类的内部维护唯一的对象:静态成员变量
#include <iostream>
class A {
private:
static A m_a;//使用静态成员来确保唯一对象
};
int main(){
return 0;
}
- 提供单例对象的访问方法:静态成员函数
#include <iostream>
class A{
public:
//使用静态成员函数来提供唯一对象的访问方式,可以直接通过类名来直接访问静态成员函数,如果使用普通成员函数,只能使用对象来调用接口函数,但是违背类唯一对象的原则
static A& getA(void){
return m_a;
}
private:
static A m_a;
};
int main(){
A::get();
return 0;
}
- 创建方式
饿汉式
单例对象无论用或者是不用,程序启动即创建
优点:代码实现简单,在多线程里是安全的,访问效率高
缺点:浪费内存
#include <iostream>
using namespace std;
class Singleton{
public:
//提供公开的静态成员函数来获取唯一的对象
static Singleton& getInstance(void){
//返回值加上引用的作用是避免出现拷贝构造,在返回是避免出现临时对象
return s_instance;
}
private:
//1.私有化构造函数包括拷贝构造
Singleton(int data):m_data(data){
cout<<"单例对象被创建啦"<<endl;
}
Singleton(const Singleton&);
//2.使用静态成员变量来表示唯一的对象
static Singleton s_instance;
private:
int m_data;
};
Singleton Singleton::s_instance(123);
int main (void){
cout << "main run" << endl;
/*
Singleton s1(123);
//报错
因为Singleton类的构造函数被定义为类私有成员函数,只有类的内部成员可以访问,在类的外部是访问不了的
*/
//通过类中提供的共有函数来获取唯一对象的引用
Singleton& s1 = Singleton::getInstance();
Singleton& s2 = Singleton::getInstance();
Singleton& s3 = Singleton::getInstance();
/*
Singleton s4 = s3;
//error: ‘Singleton::Singleton(const Singleton&)’ is private within this context
// 36 | Singleton s4 = s3;
//拷贝构造是私有的,在类的外部不能访问
*/
cout<<"s1: "<<&s1<<endl;
cout<<"s2: "<<&s2<<endl;
cout<<"s3: "<<&s3<<endl;
}
运行结果
单例对象被创建啦
main run
s1: 0x557fe5f78154
s2: 0x557fe5f78154
s3: 0x557fe5f78154
进程已结束,退出代码 0
懒汉式
单例对象使用时在创建,不用即销毁
优点节省内存
缺点代码实现复杂
销毁时加入计数判断
多线程需要加互斥锁保护
效率较低
单例模式综合代码模板
#include <iostream>
#include <mutex>
using namespace std;
/*
* 单例模式
* 饿汉式(空间换时间)
* 单例对象无论用或者不用,程序创建即启动
* 懒汉式(时间换空间)
* 单例对象用时在创建,不用即销毁
*/
//线程安全的懒汉单例模式
//程序需要时创建,程序不需要时即销毁
class lazySingleton {
private:
//私有化构造函数和拷贝构造
lazySingleton() {
cout << "!!!create lazySingleton!!!" << endl;
}
lazySingleton(const lazySingleton &) = default;
~lazySingleton() {
cout << "!!!~lazySingleton()!!!" << endl;
}
//使用静态指针来维护唯一的对象指针
static lazySingleton *p;
//互斥锁
static pthread_mutex_t mutex;
//单例对象使用个数
static int count;
public:
//单例对象指针的获取接口
//仅仅第一次调用时会创建单例对象,多次调用将会得到相同的指针
static lazySingleton *getSingleton();
//单例对象释放接口
//根据单例对象的使用数量来判断是否释放,仅仅当使用数为0时才会真正释放单例对象
//当单例对象被真正释放时,计数值为零
static int release();
};
//初始化单例对象指针,互斥锁,计数值
lazySingleton *lazySingleton::p = nullptr;
pthread_mutex_t lazySingleton::mutex = PTHREAD_MUTEX_INITIALIZER;
int lazySingleton::count = 0;
//获取单例对象指针接口实现
lazySingleton *lazySingleton::getSingleton() {
//加锁
// 这里使用了两个 if判断语句的技术称为双检锁;好处是,只有判断指针为空的时候才加锁,
// 避免每次调用 GetInstance的方法都加锁,锁的开销毕竟还是有点大的。
if (!p) {
pthread_mutex_lock(&mutex);
if (!p)
p = new lazySingleton();
//解锁
pthread_mutex_unlock(&mutex);
++count;
} else {
++count;
}
return p;
}
//单例对象释放接口
int lazySingleton::release() {
//加锁
//仅仅当p非NULL时才会进行加锁操作
if (p) {
pthread_mutex_lock(&mutex);
if (--count == 0) {
delete p;
p = nullptr;
std::cout << "delete lazy singleton" << std::endl;
}
//解锁
pthread_mutex_unlock(&mutex);
}
return count;
}
//----------------------------------------------------------------
//饿汉
//程序创建即生成,程序销毁即释放
class hangrySingleton {
private:
//私有化构造和拷贝构造
hangrySingleton() {
cout << "!!!create hangrySingleton!!!" << endl;
}
hangrySingleton(const hangrySingleton &) = default;
~hangrySingleton() {
cout << "!!!~hangrySingleton()!!!" << endl;
}
static hangrySingleton *m_instancePoint;
public:
static hangrySingleton *getSingleton();
};
hangrySingleton* hangrySingleton::m_instancePoint = new hangrySingleton();
hangrySingleton *hangrySingleton::getSingleton() {
return m_instancePoint;
}
//-------------------------------------------------------------------
int main() {
std::cout << "Code running" << std::endl;
//通过类中提供的共有成员函数来获取单例对象
hangrySingleton *hangryTest1 = hangrySingleton::getSingleton();
lazySingleton *lazyTest1 = lazySingleton::getSingleton();
cout << "first get\n"
"hangry instance:" << hangryTest1 << endl <<
"lazy instance:" << lazyTest1 << endl;
hangrySingleton *hangryTest2 = hangrySingleton::getSingleton();
lazySingleton *lazyTest2 = lazySingleton::getSingleton();
cout << "second get\n"
"hangry instance:" << hangryTest2 << endl <<
"lazy instance:" << lazyTest2 << endl;
hangrySingleton *hangryTest3 = hangrySingleton::getSingleton();
lazySingleton *lazyTest3 = lazySingleton::getSingleton();
cout << "three get\n"
"hangry instance:" << hangryTest3 << endl <<
"lazy instance:" << lazyTest3 << endl;
if (hangryTest1 == hangryTest2 && hangryTest2 == hangryTest3)
cout << "hangry test success" << endl;
if (lazyTest1 == lazyTest2 && lazyTest2 == lazyTest3)
cout << "lazy test success" << endl;
cout << "first release\n"
"singleton count :" << lazySingleton::release() << endl;
cout << "second release\n"
"singleton count :" << lazySingleton::release() << endl;
cout << "three release\n"
"singleton count :" << lazySingleton::release() << endl;
return 0;
}
/home/panda/WorkSpace/Singleton/cmake-build-debug/Singleton
!!!create hangrySingleton!!!
Code running
!!!create lazySingleton!!!
first get
hangry instance:0x5607a8913eb0
lazy instance:0x5607a89142e0
second get
hangry instance:0x5607a8913eb0
lazy instance:0x5607a89142e0
three get
hangry instance:0x5607a8913eb0
lazy instance:0x5607a89142e0
hangry test success
lazy test success
first release
singleton count :2
second release
singleton count :1
three release
singleton count :!!!~lazySingleton()!!!
delete lazy singleton
0
进程已结束,退出代码 0