More Effective C++ 26:限制某个类所能产生的对象数量

本文介绍了如何在C++中限制某个类的对象数量,特别是通过单例模式实现限制为一个对象。文章探讨了使用私有构造函数、静态成员和友元函数来控制对象创建,以及在类的静态成员、全局函数和命名空间中的应用。同时,讨论了限制对象数量的挑战,如在继承和多态环境下的问题,并提出了一个具有对象计数功能的基类模板解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

例如你在系统中只有一台打印机,所以你想用某种方式把打印机对象数目限定为一个。或者你仅仅取得 16 个可分发出去的文件描述符,所以应该确保文件描述符对象存在的数目不能超过 16 个。你如何能够做到这些呢?如何去限制对象的数量呢?

每次实例化一个对象时,我们很确切地知道一件事情:“将调用一个构造函数。”事实确实这样,阻止建立某个类的对象,最容易的方法就是把该类的构造函数声明在类的 private域或者声明为delete

class CantBeInstantiated 
{
   
    
private: 
	CantBeInstantiated(); 
	CantBeInstantiated(const CantBeInstantiated&); 
	... 
};

或者:

class CantBeInstantiated 
{
   
    
public: 
	CantBeInstantiated() = delete;
	CantBeInstantiated(const CantBeInstantiated&) = delete;
	... 
};

这样做以后,每个人都没有权利建立对象,我们能够有选择性地放松这个限制。例如如果想为打印机建立类,但是要遵守我们只有一个对象可以用的约束,我们应该把打印机对象封装在一个函数内,以便让每一个人都能够访问打印机,但是只有一个打印机对象被建立:

class PrintJob; //前向声明
class Printer 
{
   
    
public: 
	void submitJob(const PrintJob& job); 
	void reset(); 
	void performSelfTest(); 
	... 
	friend Printer& thePrinter(); 
	private: 
	Printer(); 
	Printer(const Printer& rhs); 
	... 
}; 
Printer& thePrinter() 
{
   
    
	static Printer p; // 单个打印机对象 
	return p; 
}

这个设计由三个部分组成,
第一、Printer 类的构造函数是 private。这样能阻止建立对象。
第二、全局函数 thePrinter 被声明为类的友元,让 thePrinter 避免私有构造函数引起的限制。
最后 thePrinter 包含一个静态 Printer 对象,这意味着只有一个对象被建立。 客户端代码无论何时要与系统的打印机进行交互访问,它都要使用 thePrinter 函数:

class PrintJob 
{
   
    
public: 
	PrintJob(const string& whatToPrint); 
	... 
}; 
	string buffer; 
	... //填充 buffer 
	thePrinter().reset(); 
	thePrinter().submitJob(buffer);

当然你感到 thePrinter 使用全局命名空间完全是多余的,你可能会想把所有与打印有关的功能都放到 Printer 类里。这很简单,只要在 Prihter 类中声明 thePrinter 为静态函数,然后把它放在你想放的位置。就不再需要友元声明了。使用静态函数,如下所示:

class Printer 
{
   
    
public: 
	static Printer& thePrinter(); 
	... 
private: 
	Printer(); 
	Printer(const Printer& rhs); 
	... 
}; 
Printer& Printer::thePrinter() 
{
   
    
	static Printer p; 
	return p; 
} 
	用户使用 printer 时有些繁琐: 
Printer::thePrinter().reset(); 
Printer::thePrinter().submitJob(buffer);

另一种方法是把 thePrinter 移出全局域,放入 namespace(命名空间)。
Printer 类和thePrinter 函数放入一个命名空间,我们就不用担心别人也会使用 PrinterthePrinter名字;命名空间能够防止命名冲突。
如下所示,我们把 PrinterthePrinter 放入叫做 PrintingStuff 的命名空间里:

namespace PrintingStuff 
{
   
    
	class Printer // 在命名空间PrintingStuff 中的类 
	{
   
    
	public: 
		void submitJob(const PrintJob& job); 
		
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值