From: jamshid@ut-emx.uucp (Jamshid Afshar)
Newsgroups: comp.lang.c++
Subject: Re: static "inheritance" question
Summary: I think I have the solution (actually, everybody seemed to have part of it)
Date: 11 Jan 93 01:35:51 GMT
Reply-To: jamshid@emx.utexas.edu
Organization: The University of Texas at Austin; Austin, Texas

I quote a few different articles below -- watch the attrib lines.

In article <1993Jan4.144320.5586@dayfac.cdc.com> pault@dayfac.cdc.com (Paul Thompson;DAYFAC-ITS;) writes:
>Consider class A which counts its 'live' instantiations.
> 
>            class A { 
>                static int nr;
>              public:
>                A() {nr++;}
>               ~A() {nr--;}
>                int getNrInstances () {return nr;}
>            };
>            ...
>            A::nr = 0;

Note that this code would not keep an accurate count since A doesn't
also define a copy-ctor which incremements 'nr'.  I realize it's just
sample code, but forgetting about the compiler-generated copy-ctor in
situations like this is a common error.

Paul continues:
>[...]
>Could anyone enlighten me as to how to acquire the functionality
>of a class like A that depends on a static variable with LEAST
>modification to the acquiring class ? Thanks.

maxtal@extro.ucc.su.OZ.AU (John MAX Skaller) answers in article <1993Jan5.051940.28930@ucc.su.OZ.AU>
|	IF: you want to count all objects allocated (of any type):
|
|	Sure: two type of class: base classes and working 
|classes. The base classes NEVER inherit A.
|The working classes inherit from A when you want a counter.
|It is not allowed to derive from a working class though.
|[code deleted]

Not allowing one to derive from the "working" class is too serious a
restriction, IMHO.

John continues:
|IF: you want to partition the counts, you can do this:
|
|	class C1 {}; class C1 {}; class C3 {};
|
|and now make 'A' a template class and use A<C1>, A<C2> or A<C3>
|as appropriate.

I'm not sure what you mean here.  Are the Cs supposed to inherit from
A<Cx>?

John continues:
|IF: you want to count instances of EACH class, you must
|declare the static variable for each class .. no getting
|around this. However, you CAN automate the increment
|and decrement somewhat:
|
|	class Counter {
|		virtual int* counter()=0;
|	public:
|		Counter() { (*counter())++; }
|		~Counter() { (*counter())--; }
|		int TellCount()const {return *counter();}
|	};
|[...]
|#define autocount public virtual Counter { static ....
|	class X : autocount
|	...
|	};
|
|(Yuk)
|(PS: I havent tested this)

Famous last words :-).  I do agree it would be a yucky solution, but
fortunately it just doesn't work.  The Counter ctor/dtor are calling
a virtual function (and a pure one at that) -- make sure your
compiler sternly warns about this.

I think I have a pretty good solution -- it only requires the class
derive from (or contain a) KeepCount<T>, and it is safe.  John was
on the right track making the counter class a template.  I'm going to
walk through the steps I took to reach the solution since I found it
to be a very interesting problem to solve.  First, I started with a
KeepCount class similar to A above.  Any class wanting a "live count"
would derive from KeepCount.  Since each class should have its own
count, KeepCount must be a class template.  With a little work, you
could probably simulate KeepCount using <generic.h> if your compiler
doesn't implement templates yet.

      template<class T>
      class KeepCount {
         static unsigned n;   // each 'T' has its own 'n'
      protected:  // KeepCount only useful as base class
         KeepCount() { ++n; }
         KeepCount(const KeepCount&) { ++n; }
         ~KeepCount() { --n; }
      public:
         static unsigned count() { return n; }
      };
      template<class T> unsigned KeyCount<T>::n = 0; // in KeyCount.cc

      class A : public KeyCount<A> {/*...*/};

"A::count()" would then give you the current number of live A objects
[btw, I just noticed Nikke Locke posted this same solution].  But, I
think a major problem with this solution is when you derive from A.

      class B : public A {/*...*/};

"B::count()" would actually return the total number of A objects. Even
if B kept its own count by inheriting from KeepCount<B>, B must
provide its own definition of "count()" since "B::count()" would
otherwise be ambiguous:

      class B : public A, public KeyCount<B> {
      public:
         static unsigned count() { return KeyCount<B>::count(); } // tedious
      };

The key to solving this problem is to use KeyCount<X>::count()
instead of X::count() [and I just noticed that Howard Ferguson wrote
pretty much the same thing in <1ikeekINN1sb@news.cerf.net>].  We
could even make X privately inherit from KeyCount<X> to make sure
noone accidentally uses X::count().  There's still one problem with
this, though -- there's no safeguard verifying the class X really did
inherit from KeyCount<X>. KeyCount<X>::count() would just always
return 0 if X didn't derive from KeyCount<X>.  My first idea for
solving this problem was:

      template<class T>
      class KeepCount {
         static unsigned n;
         // rest same as above
      public:
         static unsigned count() {
            return T::n;   // error if T not derived from KeepCount
            }
      };

The problem with this (otherwise elegant, IMO) solution is that
"T::n" is ambigous in derived classes.

      class B : public A, public KeyCount<B> {
      };
      // B::n is ambigous (A's KeyCount<A>::n or KeyCount<B>::n?)

Also, there's the possibility that the name 'n' would be defined by
the class B.  So, I decided to use the unqualified 'n' in count(), but
build some sort of safeguard into the count() function so that it
would give a compile-time error if the class forgot to inherit from
KeyCount:

      template<class T>
      class KeepCount {
         //... same as above
      public:
         static unsigned count() {
            KeepCount* test = (T*)0;  // make sure T derived from me
            return n;
            }
      };
      class A : KeepCount<A> {};
      // "KeepCount<A>::count()" returns number of live A objects
      class B : public A, KeepCount<B> {};
      // "KeepCount<B>::count()" returns number of live B objects
      class C : public A {};
      // "KeepCount<C>::count()" is compile-time error

That's it.  Comments?  A couple of BC++ 3.1 problems: count() has to
be defined outside the class and not inlined -- BC++ parses count()
before its even used, and this causes a problem since the T is not
fully defined.  I believe Standard C++ will require the above code
work as expected.  Also, BC++ seems to allow "X* x = (Y*)0" even if Y
is not derived from X.  You have to add a dummy intermediate variable:
      T* hack=0; KeepCount* test = hack; // make sure T derived from KeepCount
Finally, BC++ 3.1 doesn't actually give a compile-time error for
count() in situations like "KeepCount<C>::count()" above.  Instead it
seems to simply ignore the template function definition and gives a
link error that KeepCount<C>::count was not defined.

John writes in another article:
|You would have to do something like:
|
|	class B : public virtual A<B> { ...
|
|which seems dubious. Then the template class A<T> could create
|the int A<T>::counter automagically. Dont know if this
|works.

No, that's fine -- you just provide a static member definition for
'counter' as you would for a non-template class.  But, I see no
reason to inherit virtually from A<B>.  You won't be inheriting
from another A<B> (unless it's through another B).

In article <1ikeekINN1sb@news.cerf.net> hlf@nic.cerf.net (Howard Ferguson) writes:
]1. If you are going to inherit make A an abstract data type by
]making its destructor a pure virtual function (see Meyers Effective
]C+, item 14)

You wouldn't want to make ~A() pure since it must do some work
(decrement the "live" count).  I don't see much reason to make it
virtual since 'A*'s will not be used.

]2.  You probably do not want to inherit anyway because inheriting 
]means you want to model IS_A, and this is not the case.

I don't think inheritance in this situation is a bad design.  I can't
see any strong reason to choose either private inheritance or
containment.  I would probably base it on compiler efficiency --
would it still take up space for an empty member vs. an empty base
class?  I don't think C++ requires space for either, so even this is
probably not a good determiner of which to use.  But I will say that
inhertance, like other C++ features, are often useful for non-OOD
reasons.

Working code is appended.

Jamshid Afshar
jamshid@emx.utexas.edu

// compiles under BC++ 3.1; "##" comments mark BC++ bugs

#include <assert.h>

template<class T>
class KeepCount {
   static unsigned n;
protected:
   KeepCount() { ++n; }
   KeepCount(const KeepCount&) { ++n; }
   // define a copy-ctor in case a copy-ctor is generated in derived class
   ~KeepCount() { --n; }
public:
   static unsigned count();
};

template<class T> /*##inline*/
unsigned KeepCount<T>::count()
{
   T* hack=0; KeepCount<T>* test = hack;  //## "KeepCount* p = (T*)0;"
                                          //## should be enough
   (void)hack;  // takes care of most compilers' "variable not used" msgs
   return KeepCount<T>::n;
}

template<class T>
unsigned KeepCount<T>::n = 0;

class A : KeepCount<A> {};

class B : KeepCount<B> {};

class C : public A {};     // woops, forgot to derive from KeepCount

class D : public A, public B {};

class E : public A, public B, KeepCount<E> {};

main()
{
   assert(KeepCount<A>::count()==0);
   assert(KeepCount<B>::count()==0);
//   assert(KeepCount<C>::count()==0);   // give error (##at link time)
//   assert(KeepCount<D>::count()==0);   // give error (##at link time)
   assert(KeepCount<E>::count()==0);
   {
      A a1; B b1;
      assert(KeepCount<A>::count()==1);
      assert(KeepCount<B>::count()==1);
      {
         A a2; B b2;
         assert(KeepCount<A>::count()==2);
         assert(KeepCount<B>::count()==2);
         {
            A a3 = a2; B b3 = b2;
            assert(KeepCount<A>::count()==3);
            assert(KeepCount<B>::count()==3);
         }
         assert(KeepCount<A>::count()==2);
         assert(KeepCount<B>::count()==2);
      }
      assert(KeepCount<A>::count()==1);
      assert(KeepCount<B>::count()==1);
   }
   {
      C c;
      assert(KeepCount<A>::count()==1);
      assert(KeepCount<B>::count()==0);
      D d;
      assert(KeepCount<A>::count()==2);
      assert(KeepCount<B>::count()==1);
      E e;
      assert(KeepCount<A>::count()==3);
      assert(KeepCount<B>::count()==2);
      assert(KeepCount<E>::count()==1);
   }
   assert(KeepCount<A>::count()==0);
   assert(KeepCount<B>::count()==0);
   assert(KeepCount<E>::count()==0);
   return 0;
}
Newsgroups: comp.lang.c++