您的位置:首页 > 编程语言 > C语言/C++

C++对象计数

2013-11-06 09:28 148 查看
转载于http://www.vckbase.com/index.php/w

本文目的是实现一个实用的对C++类计数的类,同时在实现过程中指出一些容易为人忽视的C++知识。
要实现一个类的对象(实例)计数,即程序运行中此类有多少个对象存在,最容易的实现方法是使用静态数据成员。如下:

01.
class
Widget {

02.
public
:

03.
Widget() { ++count;}

04.
Widget(
const
Widget&)
{ ++count;}

05.
~Widget() { --count;}

06.

07.
static
size_t

howMany()

08.
{
return

count;}

09.

10.
private
:

11.
static
size_t

count;

12.
};

13.

14.
//cpp文件中

15.
size_t
Widget::count = 0;


注意构造函数也要增加计数,这一点很多人容易忘记。

但是如果程序中有多个需要实例计数的类,则在每个类中加入上面代码未免繁琐、易错。这种情况下,最好是实现一个通用计数类。它应该具备一下特点:

易于使用:任何需要计数的类(以下简称客户类)只要添加少数代码即可使用;

有效率:不增加客户类大小,对客户类性能没有影响;

健壮:客户类使用时,不容易误用。

下面我们将逐步实现并完善这个通用的计数类。

01.
class
Counter {

02.
public
:

03.
Counter() { ++count;}

04.
Counter(
const
Counter&)
{ ++count;}

05.
~Counter() { --count;}

06.
static
size_t

howMany()

07.
{
return

count;}

08.

09.
private
:

10.
static
size_t

count;

11.
};

12.

13.
// This still goes in an implementation file

14.
size_t
Counter::count = 0;


上面这个Counter类能否正确完成计数呢?例如:Widget类利用它来进行实例计数:

01.
// embed a Counter to count objects

02.
class
Widget {

03.
public
:

04.
.....
// all the usual public

05.
// Widget stuff

06.
static
size_t

howMany()

07.
{
return

Counter::howMany(); }

08.
private
:

09.
.....
// all the usual private

10.
// Widget stuff

11.
Counter c;

12.
};

13.

14.
//or:

15.

16.
// inherit from Counter to count objects

17.
class
Widget:
public
Counter {


18.
.....
// all the usual public

19.
// Widget stuff

20.
private
:

21.
.....
// all the usual private

22.
// Widget stuff

23.
};


对于Widget本身来说,Counter完成了任务。然而,如果我们在同一进程中还需要利用Counter来计数Fish类,显然,Counter就不能胜任,因为它只有一个静态成员变量,它会将Widget和Fish的个数一起统计。这个方案不行,怎么办?用模板!如下:

01.
template

02.
class
Counter {

03.
public
:

04.
Counter() { ++count;}

05.
Counter(
const
Counter&)
{ ++count;}

06.
~Counter() { --count;}

07.

08.
static
size_t

howMany()

09.
{
return

count;}

10.

11.
private
:

12.
static
size_t

count;

13.
};

14.

15.
// this now can go in header

16.
template
size_t

Counter::count = 0;


则上面的实现变成:

01.
// embed a Counter to count objects

02.
class
Widget {

03.
public
:

04.
.....

05.
static
size_t

howMany()

06.
{
return
Counter::howMany();}

07.
private
:

08.
.....

09.
Counter c;

10.
};

11.

12.
//or:

13.

14.
// inherit from Counter to count objects

15.
class
Widget:
public
Counter {


16.
.....

17.
};


这样,其他类就可以使用Counter计数自己的实例了,它们将互不影响。

上面两种方案都可正确实现计数,我们继续探讨这两种方案的优缺点。

首先讲public继承,即class Widget: public Counter这种方案:有经验的读者肯定会想到基类Counter的析构函数要变为虚函数。否则通过基类指针delete派生类时,结果未定义(可能导致程序crash或其他)

1.
Counter *pw =
new

Widget;
// get base class ptr to derived class object

2.
......

3.
delete
pw;
// yields undefined results if the base class lacks a virtual destructor


但一旦Counter有虚析构函数,就会给类带入vTable,多占用了空间并影响客户类的效率。解决方法可以是将析构函数作为protected成员。这样就不能delete pw,因为它会导致编译错误。

1.
template

2.
class
Counter {

3.
public
:

4.
.....

5.
protected
:

6.
~Counter() { --count;}

7.
.....

8.
};


其次,Counter作为客户类的成员变量这种方案(这时Counter的析构函数必须public)。一个明显的缺点是客户类必须定义Counter为其成员变量同时还得定义一个inline函数以调用Counter类得HowMany函数。另一个较隐蔽的缺点:它增大了客户类所占用的内存。Counter类没有非静态成员变量,有人就可能会认为Counter对象的大小为0,其实不然,C++规定所有对象的大小最小必须为1字节。所以这用方案增加了客户类的大小。使用派生则不一样,基类size可以0,所以public继承方案不会增加客户类的大小。

除了上面两种方案,还可以使用private继承,即class Widget: private Counter。类似于第一种方案:

1.
class
Widget:
private
Counter {


2.
public
:

3.
// make howMany public

4.
using
Counter::howMany;

5.

6.
.....
// rest of Widget is unchanged

7.
};


它直接防止下面的代码:

1.
Counter *pw =
new

Widget;
//私有继承不允许这样转换


综合看来,public继承方案已经比较完善了。然而,还是有些值得注意的地方。假如有另一个类SpecialWidget,其继承于Widget,对类SpecialWidget的对象计数就只能如下:

1.
class
SpecialWidget:
public
Widget,


2.
public
Counter {

3.
public
:

4.
};


这样,对SpecialWidget的对象计数是正确的,但对Widget对象的计数是错误的。这时Widget的计数是Widget类的所有对象SpecialWidget类的所有对象的总和。为什么?因为每创建一个SpecialWidget对象,Widget构造函数就要调用一次,就增加一次计数。

总结

用模板实现的这个对象计数类可以满足绝大多数需求,但不适用于计数有继承关系的类。本文的核心思想来源于CUG上C++大师Scott Meyers的一篇文章并有所改动。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: