C++特殊类设计

1.不能被拷贝的类

  如果想让一个类不能被拷贝,只需要禁掉这个类的拷贝构造和赋值运算符的重载即可。在C++11中我们可以用delete关键字来隐式删除这两个函数。

class CopyBan
{
    // ...
    CopyBan(const CopyBan&)=delete;
    CopyBan& operator=(const CopyBan&)=delete;
    //...
};

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

  只能在堆上创建也就是只能通过new或者malloc等方式创建对象。实现方式为以下两个步骤:
1.首先将构造函数私有,其次为了方式通过拷贝构造的方式在栈上创建对象,拷贝构造也要私有。

2.提供一个静态的成员函数,在这个静态的成员函数中创建对象。(在堆上)

class HeapOnly    
{     
public:     
    static HeapOnly* CreateObject()  
   {      
        return new HeapOnly;    
   }
private:    
    HeapOnly() {}
    
    // C++98
    // 1.只声明,不实现。因为实现可能会很麻烦,而你本身不需要
 // 2.声明成私有
    HeapOnly(const HeapOnly&);
        
    // C++11的实现方式    
    HeapOnly(const HeapOnly&) = delete;
};

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

   只能在栈上创建也就是不能用new等关键字。我们可以直接把new和delete的重载禁掉,同样也是提供一个静态成员函数,在这个函数里创建对象。

class StackOnly
{
public:
 static StackOnly CreateObj()
 {
 return StackOnly();
 }
    
 // 禁掉operator new可以把下面用new 调用拷贝构造申请对象给禁掉

 void* operator new(size_t size) = delete;
 void operator delete(void* p) = delete;
private:

 StackOnly()  
 :_a(0)
 {}
 int _a;
};

4.不能被继承的类 

  在C++98中,我们需要把构造函数私有,因为子类创建对象需要先调用父类的构造函数,父类构造函数私有子类就调用不到。

  但是在C++11中有更简便的方法,我们可以直接使用final关键字。

// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
class NonInherit
{
public:
 static NonInherit GetInstance()
 {
 return NonInherit();
 }
private:
 NonInherit()
 {}
};

//C++11超简洁
class A  final
{
    // ....
};

5.只能创建一个对象的类(单例模式) 

  设计模式

  设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的
总结。为什么会产生设计模式这样的东西呢?就像人类历史发展会产生兵法。最开始部落之间打
仗时都是人拼人的对砍。后来春秋战国时期,七国之间经常打仗,就发现打仗也是有套路的,后
来孙子就总结出了《孙子兵法》。孙子兵法也是类似。
  使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模
式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

单例模式

  单例模式也就是这个类只能创建一个对象。单例模式有两种实现方式:


1.饿汉模式 

  简单来说就是不管这个对象用不用,程序启动时就给它创建好了(就是在main函数调用前)。优点是简单。缺点是程序启动会变慢。

  其实程序启动变慢在公司当中还是比较坑的。因为慢的话启动时间可能会有几十分钟,慢的话一是程序猿内心的煎熬,二是我们也不知道这个程序是启动慢还是已经挂了,三是启动慢的话也确实没那么好用。四就是它可能还用不到。

  饿汉模式还有一个缺点就是如果有两个类相互依赖,那么就需要明确这两个对象的创建顺序,但是这个是不好控制,所以在这个场景下耦合度过高。

实现方法,也是将构造函数私有,并且再定义一个静态成员函数,在这个函数中返回我们一开始就创建好的对象的地址。

// 饿汉模式
// 优点:简单
// 缺点:可能会导致进程启动慢,且如果有多个单例类对象实例启动顺序不确定。
  class Singleton
 {
  public:
      static Singleton* GetInstance()
     {
          return &m_instance;
     }
  
  private:
     // 构造函数私有
    Singleton(){};
    
    // C++98 防拷贝
    Singleton(Singleton const&); 
    Singleton& operator=(Singleton const&); 
      
    // 或者用
      
    // C++11
    Singleton(Singleton const&) = delete; 
    Singleton& operator=(Singleton const&) = delete; 
  
    static Singleton m_instance;
 };
  
  Singleton Singleton::m_instance;  // 在程序入口之前就完成单例对象的初始化

2.懒汉模式

  这个是饿汉模式的优化版,相比饿汉模式,它不会程序一启动就把对象创建好,而是当我们调用的时候再创建。 

  大致思想就是在我们调用这个静态的成员函数时,在这个函数里创建对象并返回,同时要避免反复创建。它优点就是解决了饿汉的缺点,缺点就是比较复杂。

namespace lazy
{
	class Singleton
	{
	public:
		// 2、提供获取单例对象的接口函数
		static Singleton& GetInstance()
		{
			if (_psinst == nullptr)
			{
				// 第一次调用GetInstance的时候创建单例对象
				_psinst = new Singleton;
			}

			return *_psinst;
		}

		// 一般单例不用释放。
		// 特殊场景:1、中途需要显示释放  2、程序结束时,需要做一些特殊动作(如持久化)
		static void DelInstance()
		{
			if (_psinst)
			{
				delete _psinst;
				_psinst = nullptr;
			}
		}

		void Add(const pair<string, string>& kv)
		{
			_dict[kv.first] = kv.second;
		}

		void Print()
		{
			for (auto& e : _dict)
			{
				cout << e.first << ":" << e.second << endl;
			}
			cout << endl;
		}

		class GC
		{
		public:
			~GC()
			{
				lazy::Singleton::DelInstance();
			}
		};

	private:
		// 1、构造函数私有
		Singleton()
		{
			// ...
		}

		~Singleton()
		{
			cout << "~Singleton()" << endl;

			// map数据写到文件中
			FILE* fin = fopen("map.txt", "w");
			for (auto& e : _dict)
			{
				fputs(e.first.c_str(), fin);
				fputs(":", fin);
				fputs(e.second.c_str(), fin);
				fputs("\n", fin);
			}
		}

		// 3、防拷贝
		Singleton(const Singleton& s) = delete;
		Singleton& operator=(const Singleton& s) = delete;

		map<string, string> _dict;
		// ...

		static Singleton* _psinst;
		static GC _gc;
	};

	Singleton* Singleton::_psinst = nullptr;
	Singleton::GC Singleton::_gc;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值