C++的特殊类

一、单例模式

        单例模式,是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点来获取该实例。要确保只有一个实例,关键就是要ban掉构造函数以及拷贝构造和赋值拷贝,防止出现更多实例。

        在ban掉构造函数以后,要如何创建出唯一的一个实例呢?只能从静态变量这个角度来想办法解决。从单例模式的应用场景入手,单例模式通常用来统一写入日志文件、对共享设备统一管理等。因此,有饿汉模式和懒汉模式两种角度的实现方法:

1.1 饿汉模式

        饿汉模式,就是在程序启动时就完成单例的实例化,因此,无论是否会用到这个单例,只要使用了饿汉模式,程序启动,这个单例就会占用空间。但是,优势就是调用快速,实现简单:

class A {
public:
	static A& getA() {
		return a;
	}
	void Insert(pair p) {
		mss.insert(p);
	}
	void Print() {
		for (auto& e : mss) {
			cout << e.first << ":" << e.second << endl;
 		}
	}
	A& operator=(const A& a) = delete;
	A(const A& a) = delete;
private:
	A()
	{ }
	map mss;
	static A a;
};

A A::a;

int main(void) {
	
	A::getA().Insert(make_pair("apple", "苹果"));
	A::getA().Insert(make_pair("banana", "香蕉"));
	A::getA().Insert(make_pair("cat", "猫"));
	A::getA().Insert(make_pair("delete", "删除"));
	A::getA().Print();

	return 0;
}

        通过在main之前实例化静态成员变量a,再借助调用函数就可以实现单例模式的饿汉模式,全局仅有一个A的实例,因此所有的插入都是在同一个map中进行修改。

1.2 懒汉模式

        懒汉模式,则是在需要调用时才会实例化,相比饿汉模式,能控制各个单例初始化的顺序,并且由于是调用时才会实例化,没有用到的类就不会被实例化出来占用空间,且可以节省在调用main函数之前的准备时间。缺点就是第一次调用时需要时间实例化,实现更为复杂:

class B {
public:
	static B* getB() {
		if (!pb) {
			pb = new B;
		}
		return pb;
	}
	

	void Add(const string& key, const string& value)
	{
		m[key] = value;
	}

	void Print()
	{
		for (auto& kv : m)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
		cout << endl;
	}
	
private:
	B()
	{ }
	~B() {
		cout << "把数据写入硬盘" << endl;
	}
	B(const B&) = delete;
	B& operator=(const B&) = delete;
	map m;

	class gc {
	public:
		
		~gc() {
			delete pb;
			pb = nullptr;
			cout << "~B" << endl;
		}
		
	};
	static gc _gc;
	static B* pb;
};

B* B::pb = nullptr;
B::gc B::_gc;

int main(void) {
	B::getB()->Add("apple", "苹果");
	B::getB()->Add("banana", "香蕉");
	B::getB()->Add("cat", "猫");
	B::getB()->Add("delete", "删除");
	B::getB()->Print();
	
	return 0;
}

        这里用指针的形式实现懒汉模式,其实还有另一种采用静态局部变量的形式,也就是将饿汉模式的静态成员变量,放到get函数,在调用时如果没有实例化过则会实例化,如果实例化了就不会再实例化了,这里不做过多介绍。

        然后,指针的销毁通过智能指针的思想进行解决,也可以直接使用指针指针进行管理,当程序结束时,就会调用析构函数将指针销毁。这里是使用了一个静态类完成对静态指针的管理。

二、一些其他类型类的实现

2.1 不能被继承的类

        在C++98中,可以通过将父类的构造函数私有化来实现,而在C++11中则可以通过使用final关键字实现不能被继承。

2.2 不能被拷贝的类

        在C++98中,可以将拷贝构造和赋值拷贝声明在private下,这样既不能被调用,又不能在类外重写。而在C++11中,则可以简单的使用delete删除掉这两个函数,从而实现不能被拷贝。

2.3 只能在堆上创建的类

        同样也要通过限制构造函数来达成目的,再通过特定的可供调用的函数来完成构造。然后再删除掉拷贝构造和赋值拷贝,限制其他构造的手段:

class A {
public:
	static A* Initial(int a) {
		return new A(a);
	}
private:
	A(int a)
		:_a(a)
	{}
	A(const A&) = delete;
	A& operator=(const A&) = delete;
	int _a;
};

        这样就只能通过调用A::Initial函数完成构造 ,而这样构造出的类一定是堆上的类。

2.4 只能在栈上创建的类

        还是通过限制构造函数,但是,禁止掉拷贝构造函数会导致调用的构造函数无法传回构造出的类。因此,直接禁止掉new:

class A {
public:
	static A Initial(int a) {
		A tmp = A(a);
		return tmp;
	}
	A(A&&) = default;
    A& operator=(A&&) = default;
private:
	A(int a)
		:_a(a)
	{}
	void* operator new(size_t) = delete;
	A(const A&) = delete;
	A& operator=(const A&) = delete;
	int _a;
};

         这样,要在堆上创建就只能调用new但是new又被删除了,因此,只能在栈上创建。

你可能感兴趣的:(C++的特殊类)