在《C++高效编程》中有一篇文章叫做Counting Objects。主要讲述了利用模板复用静态类对象,看完觉得不错,小记一下。
一 问题
如果想要做一个统计子类实例个数的代码,比方说统计控件Widget的个数,我们会怎样写?
二 一般解法
class Counter
{
public:
Counter(){++count;}
Counter(const Counter&){++count;}
~Counter(){--Count;}
static size_t Number();
private:
size_t count;
};
size_t Counter::count = 0;
class Widget:public Counter
{
};
三 存在的问题
1.如果我想要统计一个其他类别子类的个数,Counter还能复用吗?
2.这个能阻止客户端代码调用Counter* iCount = new Widgets吗?如果调用了,delete iCount可是会造成内存泄露的。为了防止这种内存情况,Counter的析构函数必须为虚函数,这样会增加对象的空间。
四 解决方案
1.Counter对象复用
如果是上述写法,继承Counter就等于同时继承了其静态变量,会导致两种不同的统计对象相加到一起,只能再写一个和Counter一模一样的类,只不过名字不同了。但是可以运用模板解决问题,其实模板就是在编译时根据类型实例化一个特别的类。因此,Counter这样写就可以复用了.
template<typename T>
class Counter
{
public:
......(以上内部代码一样)
};
template<typename T> Counter<T>::count = 0;
class Widget:public Counter<Widget>
{
};
class OtherObject:public Counter<OtherObject>
{
};
2.阻止客户端新建子类对象赋值到父类指针
方法一: 内部私有化Counter的delete操作符,编译器编译提示删除对象不可访问,从而达到保护的目的。这种方法感觉很恶心,提示错误的地方不在new而在delete,所以不推荐.
方法二: 私有继承Counter类,只是公布需要使用的Counter类的接口;
class Widget:private Counter<Widget>
{
public:
using Counter<Widget>::Number;
};
Counter<Widget>* iCount = new Widget;
//此句编译会提示出错,error: `Counter<Widget>' is an inaccessible base of `Widget'
但是Number方法仍然可以照常使用;
利用模板实现对象复用,是C++常用的技术,也是模板的优势所在。