单例模式
把任务管理器看作是一种类,用这个类创建了个对象,如果将任务管理器删掉然后再打开。是否看作是将对象销毁后重新创建了一个对象。
其实这个对象在电脑上只有一个,而且只要电脑没有关机它是不会被释放的。有些类创建出来的对象在全局只能有一个,这个就是所谓的单例模式(唯一的实例)。
实现单例模式:
主席类
1,首先创建了一个主席类,在public下创建的话,在实现中就可以创建多个对象,调用多次的构造函数。
2,现在将构造函数私有化(构造函数的权限修改为private,这样在外面就一个也创建不了了,只能在类内使用)
3,然后创建一个public的东西来给外面使用(是共享的),写一个静态的东西(保证只有一个)。(主席是共享的,拿到了指针也就相当于拿到了主席)静态的成员类内要声明,类外要初始化。
class ChairMan
{
private:
ChairMan() {};
public:
static ChairMan* singleMan;//类内声明
};
ChairMan* ChairMan::singleMan = new ChairMan;//类外初始化
//加了ChairMan以后,这句代码就相当于在类内写的了,就能够访问到构造函数了。
int main()
{
//如果想要访问静态变量,有两种访问方式,一种是创建对象访问;另一种是通过类访问。
//这里访问singleMan没办法通过创建对象访问,因为构造函数是private的
//通过类名来访问(ChairMan::singleMan),然后用个指针来接收。
ChairMan* c1 = ChairMan::singleMan;
ChairMan* c2 = ChairMan::singleMan;
//这里的c1和c2是相等的。
}
小总结:
1,就是要实现单例模式就是保证一个类只能创建一个对象,所以先将类中的构造函数private。
2,然后手动的写一个指针变量(不能在类中直接创建对象,那么就直接创建一个指针变量,找到指针变量也就找到了对象。)
3,因为这个主席是共享的,只有一个的,所以将这个指针变量设置成public和static。
4,静态变量要在类内声明,类外初始化。初始化的时候别忘了ChairMan::
,创建个对象将地址赋值给类内的静态变量(可以调用构造函数,因为写了ChairMan::
,相当于在类内部。)
5,在main中,如果要访问这个主席,也就是访问到这个主席指针。有两种方式,直接创建对象是不行的,只能用类名访问,创建指针,然后将主席指针赋值给创建的指针。(这个时候主席指针已经是只有一个且共享的了。)
但是这个时候有个隐患,那就是主席指针是可以在外面被修改的,public给的权限包括读和改。进行修改:
把静态变量的权限改成私有化(private),对外提供一个只读的接口。getInstance(获取实例)
注意:普通的成员函数没有办法访问静态的变量的,所以这个函数也必须是static的。
class ChairMan
{
public:
static ChairMan* getInstance()
{
return singleMan;
//普通的成员函数没有办法访问静态的变量的,所以这个函数也必须是static的。
}
private:
ChairMan() {};
private:
static ChairMan* singleMan;
};
ChairMan* ChairMan::singleMan = new ChairMan;
int main()
{
ChairMan* c1 = ChairMan::getInstance();//这个时候就只能读到了,无法修改
ChairMan* c2 = ChairMan::getInstance();
//这里的c1和c2是相等的。
if (c1 = c2)
cout << "成功" << endl;
return 0;
}
这样就符合单例模式的规则,通过类只能实例化出来一个对象。
最后还有一个小问题,如果调用拷贝构造函数创建出来的c3和c1,c2是不同的。
ChairMan * c3 = new Chair(*c1);
//拿到c1的实体,然后通过拷贝构造函数创建出了c3。就是将在堆区创建了一个c1内容的副本,c3指向这个堆中的副本。
//c3和c1肯定是不一样的。(通过一个主席克隆出了新的主席,这肯定不允许的)
//只需要将拷贝构造函数屏蔽掉
class ChairMan
{
private:
ChairMan(const ChairMan &){};//这样就成功的把拷贝构造函数设置成了private。
};
//再调用上面的代码就会报错,因为没有权限。
一开始的初始化:ChairMan* ChairMan::singleMan = new ChairMan;
对象是new出来的,在堆上。但是不需要用delete来释放,因为多人在使用,而且我们拿到的也只是指针,所占的空间不大。
打印机类
//打印机,全公司就一台打印机
class Printer
{
public:
static Printer* getInstance()//提供的接口
{
return printer;//返回指针
}
private :
Printer() {};//构造函数
Printer(const Printer& p) {};//拷贝构造函数
private:
static Printer* printer;//打印机指针(声明)
};
Printer* Printer::printer = new Printer;//(初始化)
void test()
{
Printer* p1 = Printer::getInstance();//利用类中的公开静态接口获得了指针。
}
注意一点:
打印机指针的声明实在程序执行前的编译阶段执行的,而初始化工作也是在这个时候执行的,所以Printer的构造函数在编译阶段就已经执行过了一次。在main函数执行之前。
有个面试题就是:如何在调用main函数之前打印一句话,就可以使用单例模式来解决。(将话写在构造函数中,在类中设置一个静态的指针变量,在类外进行初始化,在编译阶段由于初始化会调用类中的构造函数并打印构造函数中的话)
完整代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include<string>
//打印机,全公司就一台打印机
class Printer
{
public:
static Printer* getInstance()//提供的接口
{
return printer;//返回指针
}
void printText(string text)//提供打印功能
{
cout << text << endl;
num++;
}
int num;
private :
Printer() { num = 0; };//构造函数
Printer(const Printer& p) {};//拷贝构造函数
private:
static Printer* printer;//打印机指针(声明)
};
Printer* Printer::printer = new Printer;//(初始化)
void test()
{
Printer* p1 = Printer::getInstance();//利用类中的公开静态接口获得了指针。
p1->printText("打印成功");
p1->printText("打印成功");
Printer* p2 = Printer::getInstance();//换一个人打印,用的也是同一个打印机。
p2->printText("打印成功");
cout << "总共打印了" << p1->num << "次" << endl;
}
int main()
{
test();
return 0;
}