• C++_特殊类的设计和单例模式


    学习目标:

    1.请设计一个类,不能被拷贝

    拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。

    2. 请设计一个类,只能在堆上创建对象

    实现方式:

    1. 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
    2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建。

    3. 请设计一个类,只能在栈上创建对象

    同上将构造函数私有化,然后设计静态方法创建对象返回即可。

    4. 请设计一个类,不能被继承

    1. C++98 中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
    2. C++11方法 final关键字,final修饰类,表示该类不能被继承。

    5. 请设计一个类,只能创建一个对象(单例模式)


    特殊类的设计

    1. 防拷贝类的设计

    拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。

    //防拷贝类的设计
    class BanCopy {
    public:
    	BanCopy(int value)
    		:_value(value){}
    private:
    	BanCopy(const BanCopy& bc) = delete;
    	BanCopy& operator= (const BanCopy& bc) = delete;
    	int _value;
    };
    int main()
    {
    	BanCopy bc1(1);
    	BanCopy bc2(bc1);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    2.仅堆上创建类的设计

    思路则是私有化构造函数防止随意创建对象,仅通过调用类中的静态函数来获取堆上创建的实例。

    //仅堆上创建类的设计
    class HeapOnly {
    public:
    	static HeapOnly* CreateInstance(int value)
    	{
    		return new HeapOnly(value);
    	}
    private:
    	HeapOnly(int value)
    		:_value(value){}
    
    	//也要限制一下拷贝构造,因为可以通过拷贝构造来在栈上创建对象
    	HeapOnly(const HeapOnly& ho) = delete;
    	int _value;
    };
    
    int main()
    {
    	HeapOnly ho1(1);
    	HeapOnly* ho2 = HeapOnly::CreateInstance(1);
    	HeapOnly ho3 = *ho2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述


    3.仅栈上创建类的设计

    与仅堆上创建类的设计相似,通过私有化构造函数防止随意创建对象。

    //仅栈上创建类的设计
    class StackOnly {
    public:
    	static StackOnly CreateInstance(int value)
    	{
    		return StackOnly(value);
    	}
    private:
    	StackOnly(int value)
    		:_value(value){}
    
    	//禁用new调用拷贝构造
    	void* operator new(size_t size) = delete;
    	void operator delete(void* p) = delete;
    
    	int _value;
    };
    
    int main()
    {
    	StackOnly so1(2);
    	StackOnly so2 = StackOnly::CreateInstance(2);
    	StackOnly* so3 = new StackOnly(3);
    	StackOnly* so4 = new StackOnly(so2);
    	//需要注意的是,虽然说我们可以防止在堆上创建对象,但是我们却无法阻止在静态区创建对象
    	static StackOnly so5 = StackOnly::CreateInstance(3);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    4. 不可被继承类的设计

    C++98

    class NoneInherit {
    
    private:
    	NoneInherit(int value)
    		:_value(value){}
    
    	int _value;
    };
    
    class Child : public NoneInherit {
    public:
    	Child(int value, int data)
    		:NoneInherit(value)
    		,_data(data){}
    
    private:
    	int _data;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    C++11

    使用final关键字

    class NoneInherit final{
    public:
    	NoneInherit(int value)
    		:_value(value){}
    
    private:
    	int _value;
    };
    
    class Child : public NoneInherit {
    public:
    	Child(int value, int data)
    		:NoneInherit(value)
    		,_data(data){}
    
    private:
    	int _data;
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    5.单例模式的设计

    饿汉模式

    饿汉模式意思是 当程序刚开始启动时,就自动创建对象。 因为这里我们采用了静态类成员的思路。

    class Singleton {
    public:
    	static Singleton* GetInstance()
    	{
    		return &only_instance;
    	}
    
    private:
    	Singleton(int value = 0)
    		:_value(value) {}
    
    	Singleton(Singleton const&) = delete;
    
    	Singleton& operator=(Singleton const&) = delete;
    
    	int _value;
    
    	static Singleton only_instance;
    };
    
    Singleton Singleton::only_instance;
    
    int main()
    {
    	Singleton* s = Singleton::GetInstance();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    懒汉模式

    懒汉模式区别于饿汉模式就是饿汉是程序一起的就创建的单例对象,但是懒汉则是程序运行一段时间后,需要创建再创建单例对象。

    //懒汉模式
    #include
    #include
    class Singleton {
    public:
    	static Singleton* GetInstance()
    	{
    		if (only_instance == nullptr)
    		{
    			p_mutex.lock();
    			if (only_instance == nullptr)
    			{
    				only_instance = new Singleton();
    			}
    			p_mutex.unlock();
    		}
    		return only_instance;
    	}
    
    private:
    	Singleton(int value = 0)
    		:_value(value) {}
    
    	Singleton(Singleton const&) = delete;
    
    	Singleton& operator=(Singleton const&) = delete;
    
    	int _value;
    
    	//保护线程安全 加上互斥锁
    	static std::mutex p_mutex;
    	static Singleton* only_instance;
    };
    Singleton* Singleton::only_instance = nullptr;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    这里提出一个疑问,像懒汉这种写法方式,我们的唯一实例new出来的,析构需不需要写一个delete来释放资源?
    其实可以不用写,因为是唯一实例,除非说特殊需求需要中途释放或者说确定了之后不再使用该对象就可以自己写一套destroy函数,这并没有什么难度。

    我们可以试着写一个自动回收

    #include
    #include
    class Singleton {
    public:
    	static Singleton* GetInstance()
    	{
    		if (only_instance == nullptr)
    		{
    			p_mutex.lock();
    			if (only_instance == nullptr)
    			{
    				only_instance = new Singleton();
    			}
    			p_mutex.unlock();
    		}
    		return only_instance;
    	}
    	class CGarbo {
    	public:
    		~CGarbo(){ 
    			if (only_instance)
    			{
    				std::cout << only_instance->_value << std::endl;
    				delete only_instance;
    			}
    		}
    	};
    private:
    	Singleton(int value = 0)
    		:_value(value) {}
    
    	Singleton(Singleton const&) = delete;
    
    	Singleton& operator=(Singleton const&) = delete;
    
    	int _value;
    
    	//保护线程安全 加上互斥锁
    	static std::mutex p_mutex;
    	static Singleton* only_instance;
    	static CGarbo cg;
    };
    
    std::mutex Singleton::p_mutex;
    Singleton::CGarbo Singleton::cg;
    Singleton* Singleton::only_instance = nullptr;
    
    int main()
    {
    	Singleton* s1 = Singleton::GetInstance();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    在这里插入图片描述

    C++11之后的懒汉模式

    #include
    #include
    class Singleton {
    public:
    	static Singleton* GetInstance()
    	{
    		//C++11之后路这种写法是线程安全的
    		static Singleton only_instance;
    		return &only_instance;
    	}
    
    private:
    	Singleton(int value = 0)
    		:_value(value) {}
    
    	Singleton(Singleton const&) = delete;
    
    	Singleton& operator=(Singleton const&) = delete;
    
    	int _value;
    	static std::mutex p_mutex;
    
    };
    std::mutex Singleton::p_mutex;
    
    int main()
    {
    	Singleton* s1 = Singleton::GetInstance();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

  • 相关阅读:
    蓝桥杯每日一题2023.9.16
    PAT乙级1042 字符统计
    免费、好用、强大的 Markdown 编辑器综合评测和推荐
    Redis系列:RDB内存快照提供持久化能力
    运行Spring Boot项目失败?显示java: 无法访问org.springframework.boot.SpringApplication,让我来看看~
    十六、MySql的MVCC机制&CONNECT(收官!)
    PTA 1079 延迟的回文数(Python3)
    Web前端中级探索:技术进阶与困惑之旅
    高并发秒杀项目总结
    季涨约3~8%,DRAM合约价大幅回升 | 百能云芯
  • 原文地址:https://blog.csdn.net/fengjunziya/article/details/137871275