C++ 98 和 C++ 11 中几种特殊类的设计

一、禁止拷贝的类

在某些情况下,我们希望一个类的对象不能被拷贝,以确保对象的唯一性或避免不必要的复制操作。这在处理资源管理或某些特殊对象时非常有用。

C++ 98的实现方式

将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有。

//禁止拷贝的类 C++98
class NonCopyablec98
{
private:
	NonCopyablec98(const NonCopyablec98&);
	NonCopyablec98& operator=(const NonCopyablec98);
public:
	NonCopyablec98() {}
};

C++11的实现方式

C++11因为有 =delete 所以直接用就方便点,=delete来删除拷贝构造函数和赋值运算符重载。

//禁止拷贝的类 C++11
class NoCopyablec11
{
public:
	NoCopyablec11() = default;
	NoCopyablec11(const NoCopyablec11&) = delete;
	NoCopyablec11& operator=(const NoCopyablec11&) = delete;
};

使用场景

假设我们有一个类 FileHandler,用于处理文件操作。每个文件只能被一个 FileHandler 对象打开和操作,如果允许拷贝,可能会导致多个对象同时操作同一个文件,从而引发问题。通过将 FileHandler 设计为禁止拷贝的类,可以确保文件的正确操作。

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

有时,我们希望一个类的对象只能在堆上创建,这可以通过将类的构造函数私有,并提供一个静态的成员函数来创建堆对象来实现。

C++ 98的实现方式

//只能在堆上面创建对象的类 C++ 98
class HeapOnlyc98
{
public:
	static HeapOnlyc98* CreateObject()
	{
		return new HeapOnlyc98;
	}
private:
	HeapOnlyc98() {}
	HeapOnlyc98(const HeapOnlyc98&);
	HeapOnlyc98& operator=(const HeapOnlyc98&);
};

C++11的实现方式

与 C++98 类似,但可以使用 =delete 来删除默认的构造函数

//只能在堆上面创建对象的类 C++ 11
class HeapOnly11
{
public:
	static HeapOnly11* CreateObject()
	{
		return new HeapOnly11;
	}
private:
	HeapOnly11() = delete;
	HeapOnly11(const HeapOnly11&) = delete;
	HeapOnly11& operator=(const HeapOnly11&) = delete;
};

使用场景

考虑一个数据库连接池类 DBConnectionPool,它需要在堆上创建对象,以方便管理和共享连接资源。

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

与只能在堆上创建对象的类相反,我们也可以设计一个只能在栈上创建对象的类。

C++98的实现

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

class StackOnly98 {
public:
    static StackOnly98 CreateObj() {
        return StackOnly98();
    }
private:
    StackOnly98() {}
    StackOnly98(const StackOnly98&);
    StackOnly98& operator=(const StackOnly98&);
};

C++11的实现

与 C++98 类似,但可以使用 =delete 来删除 operator new 和 operator delete。

class StackOnly11 {
public:
    static StackOnly11 CreateObj() {
        return StackOnly11();
    }
    void* operator new(size_t size) = delete;
    void operator delete(void* p) = delete;
private:
    StackOnly11() {}
};

使用场景举例:
假设我们有一个线程局部存储类 ThreadLocalStorage,它需要在每个线程的栈上创建,以确保每个线程都有自己独立的存储区域。

四、不能被继承的类

在某些情况下,我们希望一个类不能被其他类继承,以保证类的完整性和特定的行为。

C++98的实现

将拷贝构造函数声明为私有,并且不提供实现。

class NonInherit98 {
public:
    NonInherit98() {}
private:
    NonInherit98(const NonInherit98&);
};

C++11的实现

使用 final 关键字来修饰类。

class NonInherit11 final {
public:
    NonInherit11() {}
};

使用场景

考虑一个核心系统组件类 CoreComponent,它具有特定的功能和接口,并且不希望被其他类随意继承和修改,以确保系统的稳定性。

五、单例模式的类(只创建一个对象)

单例模式确保一个类只有一个实例,并提供一个全局访问点,常用于管理全局资源或共享状态。
使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

饿汉模式

就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象

//单例模式
//饿汉模式
class Singleton
{
public:
	static Singleton* GenInstance()
	{
		return &m_instance;
	}
private:
	//构造函数私有保护起来
	Singleton(){};

	//C++ 98 防拷贝
	Singleton(Singleton const&);
	Singleton& operator=(Singleton const&);

	//C++11 =delete防拷贝
	Singleton(Singleton const&) = delete;
	Singleton& operator=(Singleton const&) = delete;

	static Singleton m_instance;
};

Singleton Singleton::m_instance;//在程序入口之前完成单例对象的初始化

优点:简单易于实现
缺点:如果有多个单例进行实现会导致进程启动慢

如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源竞争,提高响应速度更好。

懒汉模式

如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取
文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,
就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载)更好。

// 懒汉模式
#include <mutex>
#include <thread>
class Singleton
{
public:
	static Singleton* GetInstance() {
		// 注意这里一定要使用Double-Check的方式加锁,才能保证效率和线程安全
		if (nullptr == m_pInstance) {
			m_mtx.lock();
			if (nullptr == m_pInstance) {
				m_pInstance = new Singleton();
			}
			m_mtx.unlock();
		}
		return m_pInstance;
	}
	// 实现一个内嵌垃圾回收类    
	class CGarbo {
	public:
			~CGarbo(){
				if (Singleton::m_pInstance)
					delete Singleton::m_pInstance;
			}
	};
	// 定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象
	static CGarbo Garbo;
private:
	// 构造函数私有
	Singleton(){};
	// 防拷贝
	Singleton(Singleton const&);
	Singleton& operator=(Singleton const&);
	static Singleton* m_pInstance; // 单例对象指针
	static mutex m_mtx;   //互斥锁
};
Singleton* Singleton::m_pInstance = nullptr;
Singleton::CGarbo Garbo;
mutex Singleton::m_mtx;
int main()
{
	thread t1([]{cout << &Singleton::GetInstance() << endl; });
	thread t2([]{cout << &Singleton::GetInstance() << endl; });
	t1.join();
	t2.join();
	cout << &Singleton::GetInstance() << endl;
	cout << &Singleton::GetInstance() << endl;
	return 0;
}

优点:第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控制。
缺点:实现起来困难

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值