特殊类设计

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

C++ 98:

template<class T>
class Copy_Ban
{
private:
	Copy_Ban(Copy_Ban<T>& cb);
	Copy_Ban<T>& operator=(Copy_Ban<T>& cb);
};

拷贝构造赋值重载 只声明不定义且私有化

C++ 11:

template<class T>
class Copy_Ban
{
public:
	Copy_Ban(Copy_Ban<T>& cb) = delete;
	Copy_Ban<T>& operator=(Copy_Ban<T>& cb) = delete;
};

error C2280: “Copy_Ban::Copy_Ban(Copy_Ban &)”: 尝试引用已删除的函数

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

核心步骤只有 3 条:

  • 将构造私有化
  • 通过特定接口创建对象
  • 将 拷贝构造 和 赋值重载 封死
class HeapOnly
{
public:
    // 2. 通过特定接口创建对象
	template<class... Args>
	static HeapOnly* GetInstance(Args... args) // static 非静态成员函数(不需要使用 this)
	{
		return new HeapOnly(args...);
	}
	
    // 3. 将 拷贝构造 和 赋值重载 封死
	HeapOnly(const HeapOnly&) = delete;
	HeapOnly& operator=(const HeapOnly&) = delete;
    
    // ...
private:
    // 1. 将构造函数私有化
	HeapOnly(int x)
		:_data(x)
	{}
	HeapOnly() {}

	int _data;
	vector<int> _v;
};

创建对象:

	HeapOnly* ho = HeapOnly::GetInstance();
	// 可以通过 ho 调用类内部的各种函数
3. 请设计一个 只能在栈上创建对象 的类
  • 将构造私有化
  • 通过特定接口创建对象
  • 将 operator new (operator delete)封死
class StackOnly
{
public:
	template<class... Args>
	static StackOnly GetInstance(Args... args)
	{
		return  StackOnly(args...);
	}
	
    // 固定写法
	void* operator new(size_t) = delete;
	void operator delete(void*) = delete;
private:
	StackOnly(int x)
		:_data(x)
	{}

	StackOnly()
	{}

	int _data;
	vector<int> _v;
};

创建对象:

	StackOnly so = StackOnly::GetInstance();
何时需要删除 operator= ?
  1. 你的类被设计成不可复制的(既不能被拷贝构造,也不能被赋值)。
  2. 你的类包含了一些不允许复制的成员,因为这些成员类型可能自己就禁止了拷贝和赋值。
4. 请设计一个 不能被继承 的类

C++ 98:

将构造函数私有化派生类(子类)无法调用基类(父类)的构造函数,则无法被继承。

struct A
{
private:
    A() {}
};

struct B : public A
{
public:
    B() {} // error C2248: “A::A”: 无法访问 private 成员(在“A”类中声明)
};

C++ 11:

使用关键词 final 修饰类。

struct A final
{
public:
	A() {}
};

struct B : public A // error C3246: “B”: 无法从“A”继承,因为它已被声明为“final”
{
public:
	B() {}
};
5. 请设计 只能创建一个对象 的类(单例模式)(不加锁)

单例模式: 一个类只能创建一个对象,并提供一个全局访问点来获取该实例。

  • 饿汉模式:单例对象在类加载时就会被创建。 单例对象的生命周期与程序的生命周期相同,从程序开始运行到程序运行结束,单例对象始终存在。

​ 缺点:1. 单例对象一旦被创建,就会一直占用内存。

​ 2. 如果单例对象创建时需要执行耗时的操作,会影响程序的启动速度 —— 单例对象在 main 函数开始之前被创建。

namespace hunger
{
	class Singleton
	{
	public:
        // 提供全局访问点来获取实例
		static Singleton* GetInstance()
		{
			return &_sint;
		}
		
        // 删除拷贝构造和赋值运算符重载,防止复制
		Singleton(const Singleton&) = delete;
		Singleton& operator=(const Singleton&) = delete;

	private:
        // 私有化构造函数
		Singleton() {}
		
        // 静态成员变量保存实例
		static Singleton _sint;
	};
	// 初始化静态成员变量
	Singleton Singleton::_sint;
}
  • 懒汉模式:单例对象在第一次被请求时才创建,节省资源。

​ 缺点: 1. 在多线程环境中,如果没有正确的线程同步机制,可能会创建多个实例,破坏单例特性

(未加锁版本)

namespace lazy
{
	class Singleton
	{
	public:
		static Singleton* GetInstance()
		{
            // 第一次被请求时,创建对象
			if (_sint == nullptr)
			{
				_sint = new Singleton;
			}
			return _sint;
		}

		static void DestroyInstance()
		{
			if (_sint)
			{
				delete _sint;
				_sint = nullptr;
			}
		}
		// 删除拷贝构造和赋值运算符重载,防止复制
		Singleton(const Singleton&) = delete;
		Singleton& operator=(const Singleton&) = delete;

	private:
        // 私有化构造函数和析构函数
		~Singleton()
		{
            cout << "~Singleton()" < endl;
		}

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

		static Singleton* _sint;
	};
	// 初始化静态成员单例对象
	Singleton* Singleton::_sint = nullptr;
}

上面这段代码有一个小缺点:需要手动调用 lazy::Singleton::DestroyInstance(); 完成单例对象的释放。

优化一下:

// version 1
namespace lazy
{
    class Singleton
    {
        // ,,,
    };
    
    struct GC
    {
        GC() {}
        ~GC() { Singleton::DestroyInstance(); }
    };
    GC gc;
}

//  version 2
namespace lazy
{
    class Singleton
    {
        // ,,,
    private:
        // 设计成内部私有类,用户就无法手动调用 GC 的析构函数,释放单例对象
        struct GC
        {
            GC() {}
            ~GC() { Singleton::DestroyInstance(); }
        };
        GC gc;
    };
}
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值