【C++学习笔记】----特殊类设计、单例模式(饿汉模式,懒汉模式)

1.只能在堆上创建对象

1.代码

//1.只能在堆上创建的对象
class HeapOnly
{
public:
	static HeapOnly* CreateObject()
	{
		return new HeapOnly;
	}
	
private:
	HeapOnly(){}

	//C++98 只声明不实现
	//HeapOnly(const HeapOnly&);
public:
	//C++11 delete
	HeapOnly(const HeapOnly&) = delete;
};
#include
void test_heaponly()
{
	HeapOnly* p = HeapOnly::CreateObject();
	shared_ptr< HeapOnly> sp(HeapOnly::CreateObject());
	//HeapOnly hp(*p);//拷贝构造也要删除掉,不然会通过默认拷贝构造,构造出在栈上的对象
}

2.总结

  • C++98将构造函数,拷贝构造私有化
  • 删除默认拷贝构造,如果不删除可能会通过拷贝构造创建一个在栈上的对象

2.只能在栈上创建对象

1.代码

//2.只能在栈上创建对象
//class StackOnly 
//{
//public:
//	static StackOnly CreateObject()
//	{
//		return StackOnly();
//	}
//private:
//	StackOnly(){}
//};

class StackOnly
{
public:
	StackOnly() {}
private:
	void* operator new (size_t size);
	void operator delete(void* p);
};
void test_stackonly()
{
	//构造函数私有化
	//StackOnly st1(StackOnly::CreateObject());
	//StackOnly* p = new StackOnly;

	//屏蔽New
	StackOnly s;
	//StackOnly* p = new StackOnly;
	//缺陷
	static StackOnly ss;//在静态区
}

2.总结

  • C++98构造函数私有化,通过静态函数创建对象
  • 屏蔽New关键字,缺点可以在静态去创建对象

3.不能被拷贝的类

1.代码

//3.不能拷贝
class CopyBan
{
public:
	CopyBan(){}
private:

	//C++98 访问权限设置为私有
	//CopyBan(const CopyBan&);
	//CopyBan& operator=(const CopyBan&);

	//C++11		删除默认拷贝构造与赋值
	CopyBan(const CopyBan&) = delete;
	CopyBan& operator=(const CopyBan&) = delete;
};
void test_copyban()
{
	CopyBan c1;
	//CopyBan c2 = c1;
}

2.总结

  • C++98将赋值和拷贝构造设置为私有
  • C++11删除默认赋值和拷贝构造

4.不能被继承的类

1.代码

//4.可以继承
class NonInherit //final修饰就不能继承了
{
public:
	NonInherit()
	{
		cout << "NonInherit()" << endl;
	}
	
private:
	
};

class NewNonInherit : public NonInherit
{
public:
	NewNonInherit(const NonInherit& n)
	{
		cout << "NewNonInherit <- NonInherit" << endl;
	}
private:
};
//不可以继承
//class NonInherit
//{
//public:
//	static NonInherit GetInstance()
//	{
//		return NonInherit();
//	}
//private:
//	NonInherit() {cout << "NonInherit()" << endl;}
//
//};
//
//class NewNonInherit : public NonInherit
//{
//public:
//	/*NewNonInherit(const NonInherit& n = NonInherit::GetInstance())//由于基类构造函数私有,无法访问,所以无法实现拷贝构造
//	{
//		cout << "NewNonInherit <- NonInherit" << endl;
//	}*/
//private:
//};

void test_noninherit()
{
	//可以继承的版本
	//NonInherit n ;
	//NewNonInherit nn(n);

	//不可以继承的版本
	//NonInherit n = NonInherit::GetInstance();
	//NewNonInherit nn(n);
}

2.总结

  • 将构造函数私有,派生类就不能继承基类的对象实现创建对象。
  • 将基类声明为final 不可继承类

5.单例模式

1.代码

#include
#include
#include
#include
//单例模式 一个类只能在全局只有一个对象
//懒汉模式->延迟加载
namespace Lazyman {
	class Singleton
	{
	public:
		static Singleton* GetInstance()
		{
			if (_pinst == NULL) //双检查->       不用每次加锁,因为只要实例化出对象之后就不会进去了
			{					//加锁主要为了保护第一次多线程实例化对象的问题,不加锁就会创建多个对象
				_mtx.lock();
				if (_pinst == NULL)
					_pinst = new Singleton;
				_mtx.unlock();
			}
			return _pinst;
		}

		//垃圾回收
		class CGarbo
		{
		public:
			~CGarbo()
			{
				if (Singleton::_pinst)
				{
					delete Singleton::_pinst;
					_pinst = nullptr;
				}
			}
		};
		static CGarbo Garbo;
		//C++11删除默认拷贝和赋值
		//Singleton&operator=(const Singleton&) = delete;
		//Singleton(const Singleton&) = delete;
	private:
		Singleton()
		{
			cout << "Singleton() " << endl;
		}
		static Singleton* _pinst;

		//C++98私有化默认拷贝和赋值
		Singleton&operator=(const Singleton&);
		Singleton(const Singleton&);

		static mutex _mtx;
	};
	mutex Singleton::_mtx;
	Singleton* Singleton::_pinst = NULL;
	Singleton::CGarbo Garbo;

	void test_singleton()
	{
		Singleton* s1 = Singleton::GetInstance();
		//Singleton s2 = *Singleton::GetInstance();
		/*cout << Singleton::GetInstance() << endl;
		cout << Singleton::GetInstance() << endl;
		cout << Singleton::GetInstance() << endl;*/
		//Singleton s3(*Singleton::GetInstance());
		cout << s1 << endl;
		cout << Singleton::GetInstance() << endl;
		//cout << &s2 << endl;
		//cout << &s3 << endl;
	}
	void test_thread()
	{
		vector<thread> vthreads;
		int n = 50;
		for (int i = 0; i < n; ++i)
		{

			vthreads.push_back(thread([]() {
				Sleep(100);
				cout << Singleton::GetInstance() << endl;

			}));
		}
		for (auto&t : vthreads)
		{
			t.join();
		}
	}
}

//饿汉模式->main之前创建
namespace Hungryman 
{
	class Singleton
	{
	public:
		static Singleton* GetInstance()
		{
			return &_inst;
		}
		Singleton(const Singleton&) = delete;
		Singleton operator=(const Singleton&) = delete;
	private:
		Singleton(){}
		static Singleton _inst;
	};
	Singleton Singleton::_inst; //在main函数之前创建,不存在线程安全的问题
								//原来C语言中如何在main函数开始前执行函数, 在gcc中,可以使用attribute关键字

	void test_singleton()
	{

	}
	void test_thread()
	{
		vector<thread> vthreads;
		int n = 50;
		for (int i = 0; i < n; ++i)
		{

			vthreads.push_back(thread([]() {
				Sleep(100);
				cout << Singleton::GetInstance() << endl;

			}));
		}
		for (auto&t : vthreads)
		{
			t.join();
		}
	}
}
int main() 
{
	//test_heaponly();
	//test_stackonly();
	//test_copyban();
	//test_noninherit();

	//Lazyman::test_singleton();
	//Lazyman::test_thread();	
	
	//Hungryman::test_thread();
	system("pause");
	return 0;
}

2.总结

  1. 什么是单例模式?如何实现单例模式?
    一个类只能实例化出一个对象,将构造函数私有化,通过静态函数创建对象。
  2. 单例模式类型
  • 懒汉模式
    1.懒汉模式,运行时加载,程序启动时比较快
    2.会存在线程安全问题,我们通过双判断和锁来解决,资源可以通过对象管理
    3.要删除默认拷贝构造和赋值
    4.运行结果对比

【C++学习笔记】----特殊类设计、单例模式(饿汉模式,懒汉模式)_第1张图片

【C++学习笔记】----特殊类设计、单例模式(饿汉模式,懒汉模式)_第2张图片


  • 饿汉模式
    1.饿汉模式,提前加载,启动时创建对象,导致程序比较慢
    2.由于在main之前就创建,不存在线程安全问题,流程简单
    3.要删除默认拷贝构造和赋值
  1. 总结
  • 懒汉模式要考虑线程安全问题,实现比较复杂,饿汉不需要,实现简单
  • 懒汉需要时创建对象,不影响程序启动,饿汉启动时创建,影响程序启动
  • 如果有多个单例类,有依赖关系,饿汉不能控制创建顺序,而懒汉可以,实际上懒汉也更实用

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