c++特殊类的设计

  • 不能被拷贝的类
  • 只能在堆上创建对象的类
  • 只能在栈上创建对象的类
  • 不能被继承的类
  • 只能创建一个对象的类

一.不能被拷贝的类

  1. c++11之前,可以将拷贝构造和赋值重载私有化
  2. c++11之后,可以将在后面+delete
class CopyBan
{
	CopyBan(const CopyBan& CB) = delete;
	CopyBan& operator=(const CopyBan& CB) = delete;	
private:
};

二.只能在堆上创建对象的类

  1. 析构私有
  2. 构造私有
//2,只能在堆上申请资源
//法一:析构函数函数私有,赋值/构造函数均不能用,因为栈中对象会自动调用析构,私有类外就调不到
class HeapOnly1
{
public:

private:
	~HeapOnly1()
	{

	}
};

//法二:构造函数私有
//       有拷贝和赋值问题,1.私有析构,2.禁用拷贝构造和赋值重载
class HeapOnly2
{
public:
	static HeapOnly2* CreateObj()
	{
		return new HeapOnly2();
	}


	HeapOnly2(const HeapOnly2& CB) = delete;
	HeapOnly2& operator=(const HeapOnly2& CB) = delete;

private:
	HeapOnly2()
	{

	}
	~HeapOnly2()
	{}
};

三.只能在栈上创建对象的类

  1. 构造私有
  2. 禁用operator new和operator delete函数
  • 这里禁不掉静态区的对象
//3.只能在栈上创建对象
// 法一:构造函数私有
// 法二:禁用operator new和operator delete
class StackOnly
{
public:

	static StackOnly CreateObj()
	{
		return StackOnly();
	}
	StackOnly(StackOnly&& CB)    //可以move
	{}

private:
	StackOnly(const StackOnly& CB) = delete;
	StackOnly& operator=(const StackOnly& CB) = delete;

	//法二:
	//void* operator new(size_t size) = delete;
	//void operator delete(void* p) = delete;

	StackOnly()
	{}

};

四.不能被继承的类

  1. c++11后,可以用final修饰
  2. c++11前,禁用析构或者构造函数。因为子类的构造函数/析构函数会自动调用父类的构造和析构,如果访问权限是私有,就访问不了
//4.设计一个类,不能被继承
//      法一:final
//      法二:构造函数私有化/析构函数私有,但必须显示调用子类的析构/构造,如果不显示调用,也是可以被继承的
class NonInherit 
{
private:
	~NonInherit()
	{}
};

class Base: NonInherit
{
public:
	//Base()
	//{}

	//~Base()
	//{}
private:
};

五.只能创建一个对象的类

1.设计模式

设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。常见的设计模式有:适配器模式,迭代器模式,工厂模式,观察者模式,单例模式(只能创建一个对象)

2.单例模式

  1. 饿汉模式:程序启动时,创建对象

构造函数私有,通过静态成员来控制访问对象
法一:饿汉模式,饿汉这里只能是对象指针,不能是对象,因为要禁用拷贝构造,所以不能返回
缺点:
1.在main函数之前就会创建对象,会拖慢程序的启动速度
2.如果两个单例对象有依赖关系,那么用饿汉模式就无法控制对象创建顺序
优点:简单,没有线程安全问题

  1. 懒汉模式:程序第一次调用对象时,创建对象

    可以解决饿汉的缺点,但比饿汉复杂,并且有线程安全问题


//5.设计一个类,只能实例化一份对象(设计模式-单例模式)
// 构造函数私有,通过静态成员来控制访问对象
//  法一:饿汉模式,饿汉这里只能是对象指针,不能是对象,因为要禁用拷贝构造,所以不能返回
//         缺点:
//                1.在main函数之前就会创建对象,会拖慢程序的启动速度
//                2.如果两个单例对象有依赖关系,那么用饿汉模式就无法控制对象创建顺序
//         优点:简单,没有线程安全问题
class SingleLeton1
{
public:

	//返回值不能是对象,因为要禁用拷贝构造,所以不能值返回
	static SingleLeton1* GetInstance() 
	{
		return _ins;
	}

	void print()
	{
		cout << _a;
	}

	void add(int x)
	{
		_a = x;
	}

private:

	//需要禁用构造和赋值重载
	SingleLeton1(const SingleLeton1& ins) = delete;
	SingleLeton1& operator=(const SingleLeton1& ins) = delete;

	SingleLeton1(int a = int(), string str = string())
		:_a(a)
		,_str(str)
	{}



private:
	int _a;
	string _str;

	//static SingleLeton1 _ins;
	static SingleLeton1* _ins;

};
SingleLeton1* SingleLeton1::_ins = new SingleLeton1();

//5.设计一个类,只能实例化一份对象(设计模式-单例模式)
// 构造函数私有,通过静态成员来控制访问对象
//  法一:懒汉模式,
//    可以解决饿汉的缺点,但比饿汉复杂,并且有线程安全问题

class SingleLeton2
{
public:

	static SingleLeton2* GetInstance()
	{
		//双检查加锁
		if (_ins != nullptr)      //增加效率,防止每次调用GetInstance都加锁减锁
		{
			_mtx.lock();

			if (_ins != nullptr)
				_ins = new SingleLeton2();

			_mtx.unlock();
		}

		return _ins;
	}

	void print()
	{
		cout << _a;
	}

	void add(int x)
	{
		_a = x;
	}

	static void DelInstance()
	{
		//这里并不需要双检查,因为不会频繁调用DelInstance
		_mtx.lock();

		if (_ins != nullptr)
			delete _ins, _ins = nullptr;

		_mtx.unlock();
	}
	~SingleLeton2()
	{
		//有时候需要持久化。。。
		//写入文件中etc
	}

	//有时候需要自动调用析构函数,那么可以使用内部类
	class GC
	{
	public:
		~GC()
		{
			cout << "~GC" << endl;
			DelInstance();
		}
	};

	static GC _gc;

private:

	//需要禁用构造和赋值重载
	SingleLeton2(const SingleLeton2& ins) = delete;
	SingleLeton2& operator=(const SingleLeton2& ins) = delete;

	SingleLeton2(int a = int(), string str = string())
		:_a(a)
		, _str(str)
	{}

private:
	int _a;
	string _str;

	//static对象必须类外初始化才能使用
	//static SingleLeton1 _ins;
	static SingleLeton2* _ins;
	static mutex _mtx;

};
SingleLeton2* SingleLeton2::_ins;
SingleLeton2::GC SingleLeton2::_gc;
mutex SingleLeton2::_mtx;
class SingleLeton21
{
public:

	static SingleLeton21& GetInstance()
	{
		//static 修饰局部变量,改变作用域,不改变生命周期
		//在c++11之前,该代码有线程安全的问题
		//在c++11之后,没有线程安全的问题
		static SingleLeton21 ins;

		return ins;
	}

	void print()
	{
		cout << _a;
	}

	void add(int x)
	{
		_a = x;
	}

	~SingleLeton21()
	{
		//有时候需要持久化。。。
		//写入文件中etc
	}

private:

	//需要禁用构造和赋值重载
	SingleLeton21(const SingleLeton21& ins) = delete;
	SingleLeton21& operator=(const SingleLeton21& ins) = delete;

	SingleLeton21(int a = int(), string str = string())
		:_a(a)
		, _str(str)
	{}

private:
	int _a;
	string _str;

	//static对象必须类外初始化才能使用
	//static SingleLeton1 _ins;


};

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