单例模式:
1.构造,拷贝构造屏蔽起来
2.在类中提供一个接口 生成唯一对象
(1.不能返回类类型;2.不能依赖对象的调用)
#include<iostream>
using namespace std;
//校长类
class Master
{
public:
static Master *getInstance(char* name, int age)//摆脱于对对象的依赖
{
if (pma == NULL)
{
pma = new Master(name,age);
}
return pma;
}
private:
Master(char* name, int age) :mname(new char[strlen(name) + 1])
{
strcpy(mname, name);
mage = age;
}
Master(const Master&);//声明而已
//不会调用拷贝构造,因为拷贝构造是用一个已存在的对象来生成新对象
char* mname;
int mage;
static Master* pma;//堆上
//静态不属于对象所私有,是属于作用域的
};
Master* Master::pma = NULL;//静态成员需要在类外进行初始化
int main()
{
Master* pma1 = Master::getInstance("zhangsan", 18);
Master* pma2 = Master::getInstance("zhangsan", 18);
Master* pma3 = Master::getInstance("zhangsan", 18);
Master* pma4 = Master::getInstance("zhangsan", 18);
return 0;
}
类中接口的返回值:
Master 以类类型返回会生成临时对象
Master* Master& 返回指针、引用都可以
类中接口需要设置为静态:
普通成员方法: _thiscall调用约定,依赖于对象的调用
该接口是用来生成对象的,但该接口又依赖于对象的调用,无法使用
故为 static Master *getInstance(char* name, int age); //需摆脱于对对象的依赖
验证是同一个对象,调试结果:
从调试程序中可以看出,指针永远指向唯一的对象,因为整个类只能生成一个对象。
如果是多线程情况下,还会存在线程安全的问题:(假设有A、B两个线程)
假如A先进行到 if(psing==NULL)这步,判断条件为true,恰巧这时时间片到了,B运行这个程序,此时B也进行到这一步,判断条件为true,然后创建了一个对象,这时B时间片到了,轮到了A向下执行,此时因为A之前已经判断过,所以不再判断,接着上次继续向下执行,这样就会把psing指向B的指针断裂,会存在内存泄漏问题,并会生成两个对象,不满足单例模式。
解决方案:给临界区代码加锁
static SingleTon * getIntance()
{
if(psing==NULL)
{
//lock()
if (psing == NULL)
{
psing = new SingleTon();
}
//unlock
}
return psing;
}
这种模式叫做:双重锁机制的单例模式
此外,还有一种方式,即在进程开启之前,就已生成对象,这样便不会在这方面出现线程安全问题。
方案:在类中生成对象, 在 .data段,设置为静态 static
#include<iostream>
using namespace std;
class SingleTon
{
public:
static SingleTon& getIntance()
{
return single;
}
private:
SingleTon(){}
SingleTon(const SingleTon&);
static SingleTon single;//生成的对象在 .data段
};
SingleTon SingleTon::single;//调用默认的构造函数,在main之前,对象就已生成
int main()
{
//SingleTon single = SingleTon::getIntance();//报错,调用拷贝
SingleTon& single = SingleTon::getIntance();
return 0;
}
调试结果:
可以看出,single1还未生成,single已经生成。
接着single1才生成。