C++知识点 -- 特殊类设计

C++知识点 – 特殊类设计


一、不能被拷贝的类

不让编译器默认生成拷贝构造和赋值重载,c++11可以在默认成员函数后加上 = delete,表示让编译器删除该默认成员函数;

class CopyBan
{
    
    
public:
	CopyBan(const CopyBan& cb) = delete;
	CopyBan& operator=(const CopyBan& cb) = delete;

private:

	int _a;
};

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

在这里插入图片描述
对于普通类,在栈、堆和静态区都能够创建对象;
要设计只能在堆上创建对象的类,就需要堆构造函数或者析构函数做出一定调整;

方法一
析构函数设为私有,这样在栈和静态区的对象就无法调用析构函数销毁对象,只有在对上创建的对象调用delete才能够销毁对象,可以写一个公有函数来delete对象,完成对象的销毁;

class HeapOnly
{
    
    
public:
	//公有函数调用delete销毁对象,设置成静态成员,使用类域就能够调用
	static void Delete(HeapOnly* p)
	{
    
    
		delete p;
	}

private:
	//析构函数私有化
	~HeapOnly()
	{
    
    }

	int _a;
};

在这里插入图片描述
可以看出,栈和静态区都无法创建StackOnly对象,只有通过new才能在堆上创建对象;

方法二
构造函数私有化,这样在哪里都无法创建对象了,再添加一个公有的静态成员函数,完成函数内部在堆上创建对象,同时将拷贝构造和赋值重载也设为私有,否则还能通过拷贝的方式在其他地方创建对象;

class HeapOnly
{
    
    
public:
	//提供一个公有的,在堆上创建对象的方式
	static HeapOnly* CreatObj()
	{
    
    
		HeapOnly* pho = new HeapOnly;
		return pho;
	}

private:

	//构造函数私有化
	HeapOnly()
	{
    
    }
	//拷贝构造和赋值重载也删除
	HeapOnly(const HeapOnly& so) = delete;
	HeapOnly& operator=(const HeapOnly& so) = delete;

	int _a;
};

在这里插入图片描述
效果一样;

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

构造函数私有化,提供一个公有的静态成员函数,函数内部调用构造函数在堆上创建对象,返回该对象

但是这种方式并不能阻止拷贝构造在其他地方创建对象,简单地将拷贝构造和赋值重载delete,会导致CreateObj这个函数传值返回出问题,因为传值返回需要调用拷贝构造,我们可以通过delete掉operator new来限制new创建对象

class StackOnly
{
    
    
public:
	static StackOnly CreateObj()
	{
    
    
		StackOnly so;
		return so;
	}

private:
	StackOnly()
		: _a(0)
	{
    
    }

	void* operator new(size_t n) = delete;

	int _a;
};

在这里插入图片描述
这种方法并不能防止在静态区创建对象;

四、 不能被继承的类

在c++11中,用final修饰一个类,表示该类不能被继承;

//该类无法被继承
class A final
{
    
    

};

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

一个类只能创建一个对象,就是单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享;
单例模式有两种实现:

1.饿汉模式

程序启动时就创建一个唯一实例对象;
(1)构造函数私有化,就不能通过其他方式初始化了;
(2)私有成员中声明一个静态的指向该对象的指针,静态成员属于这个类;
(3)在类外使用new初始化这个静态指针;
(4)提供公有函数来返回这个指向对象的静态指针;

class Singleton
{
    
    
public:
	static Singleton* GetInstace()
	{
    
    
		return _pinst;
	}

	void* Alloc(size_t n)
	{
    
    
		void* ptr = nullptr;
		//...
		return ptr;
	}

	void Delloc(void* ptr)
	{
    
    
		//...
	}

private:
	//构造函数私有化
	Singleton()
	{
    
    }

	char* _ptr = nullptr;
	static Singleton* _pinst;//声明
};

//定义
Singleton* Singleton::_pinst = new Singleton;

//使用
void test()
{
    
    
	void* ptr1 = Singleton::GetInstace()->Alloc(10);
	Singleton::GetInstace()->Delloc(ptr1);

}

优点:简单、没有线程安全问题
缺点:
(1)一个程序中,多个单例,并且有先后创建初始化顺序要求时,饿汉无法控制。
比如程序两个单例类A 和 B,假设要求A先创建初始化,B再创建初始化。
(2)饿汉单例类,初始化时任务多,会影响程序启动速度。

2.懒汉模式

第一次使用对象时才创建实例对象;
(1)构造函数私有化,私有静态对象指针;
(2)公有静态成员函数,只有在对象指针为空的时候才创建对象,返回指向对象的指针;
(3)需要释放资源的场景,可以内嵌一个垃圾回收类;
实例化出一个静态垃圾回收对象,出了对象作用域(main函数结束后)就会调用析构,在析构里面将单例对象的资源全部释放;

class Singleton
{
    
    
public:
	static Singleton* GetInstance()
	{
    
    
		if (_pinst == nullptr)
		{
    
    
			_pinst = new Singleton;
		}

		return _pinst;
	}

	void* Alloc(size_t n)
	{
    
    
		void* ptr = nullptr;
		//...
		return ptr;
	}

	void Delloc(void* ptr)
	{
    
    
		//...
	}

	//内嵌垃圾回收类
	class CGarbo
	{
    
    
	public:
		~CGarbo()
		{
    
    
			if (_pinst)
			{
    
    
				delete _pinst;
			}
		}
	};

private:
	//构造函数私有化
	Singleton()
	{
    
    }

	char* _ptr = nullptr;
	static Singleton* _pinst;//声明
};

//定义
Singleton* Singleton::_pinst = nullptr;

//回收对象:main函数结束后,会调用析构函数,就会释放单例对象
static Singleton::CGarbo gc;


void test()
{
    
    
	void* ptr1 = Singleton::GetInstance()->Alloc(10);
	Singleton::GetInstance()->Delloc(ptr1);
}

优点:
(1)控制顺序
(2)不影响启动速度
缺点:
(1)相对复杂
(2)线程安全问题要处理好

3. 单例对象释放问题:

(1)一般情况下,单例对象不需要释放的。因为一般整个程序运行期间都可能会用它。
单例对象在进程正常结束后,也会资源释放。
(2)有些特殊场景需要释放,比如单例对象析构时,要进行一些持久化(往文件、数据库写)操作。

猜你喜欢

转载自blog.csdn.net/kissland96166/article/details/130582444
今日推荐