is there any way to make all derived classes count their instances?How (write code in one of C++, C#, Java)?
Imagine I've got access to the root class (e.g. object), and every other class is (directly or indirectly) derived from this class. What I want is:
AnyDerivedClass.InstancesCount()
Problem is, one must keep track of count in static variable, but it is not possible to "inject" static variable into derived class from base class, this holds only for member variables. That is, I have to write something like:
class object
{
private static int count = 0;
protected object() { ++count; }
protected ~object() { --count; }
public static InstancesCount() { return count; }
};
class derived : object
{
private static int count = 0;
public derived() { ++count; }
public ~derived() { --count; }
public static InstancesCount() { return count; }
}
This functionality is obviously repeated, and I cannot put it in base class. Note there are 2 ways of calculating: that if there are 7 instances of class derived1 and 8 instances of class derived2, there are (a) 15 instances of object or (b) 0 instances of object. I don't care which one, because I can't do neither (using reasonably practical means, e.g. imagine 100 classes, half of which are in library I cannot modify).
Of course, in theory it is possible to create map of (some run-type type identifier) => int count, and use ugly, slow, (run-time type)-based approach (at least in C#, Java).
Of course, if I can modify derived classes, I can use copy-paste (awful), macro (yeah I know), mixins (not in these languages) etc. But that is still real ugly.
This is specific problem, but It happened to me several times, that I'd like to be able to "inject" static member into derived class to solve problem elegantly.
Help much appreciated.
EDIT: thanks for good answer, in C++ it is possibly to use CRTP (Curiously recurring template pattern) as well, but not in C#/Java (no multiple inheritance). Of course, one must have access to derived classes and add this base class, so question remains (in case there is no other way, this looks best).
EDIT 2: looks impossible with current languages. static part of every class is not inheriting (and that's right), but there is no inheriting singleton associated with every class, so these kinds of problems cannot be solved so elegantly. To illustrate things, look at the following code: normal members and static members are current OOP languages feature, "singleton" (or whatever word would be) members are my suggestion/desire:
class Base
{
static int sMemberBase;
int memberBase;
//my wish (note that virtual for methods is allowed!):
singleton int singletonMemberBase;
};
class Derived : Base
{
static int sMemberDerived;
int memberDerived;
//my wish (note that virtual for methods is allowed!):
singleton int singletonMemberDerived;
};
//taken apart: (note: XYZStatic classes do not derive)
class Base { int memberBase; }
class BaseStatic { int sMemberBase; } BaseStaticInstance;
class Derived : Base { int memberDerived; }
class DerivedStatic { int sMemberDerived; } BaseStaticInstance;
//note: Derived::sMemberBase is compile-time changed to Base::sMemberBase
//my wish: (note inheritance!)
class BaseSingleton { int singletonMemberBase; } BaseSingletonInstance;
class DerivedSingleton : BaseSingleton { int singletonMemberDerived; } DerivedSingletonInstance;
If anything like that would be present in language, solution for my question would be simple and elegant:
//with singleton members, I could write counter like this:
class object
{
singleton int count;
object() { ++count; }
~object() { --count; }
};
In Java you can implement the counting function to the common super class of your hirachy. This base class contains a Map - associating the classes to the number of instances. If a instance of base or one of its sub class is created, then the constructor ins invoked.
Instances of a class mean the objects created for a particular class. A single class can have multiple objects of it. Here, we will find the count of the number of instances of a class in Python. Whenever an object is created, the constructor of that particular class is called.
print ("Number of instances:", cls.numlnstances) printNumlnstances = classmethod (printNumlnstances) This class is used in the same way as the prior versions, but its printNumInstances method receives the class, not the instance, when called from both the class and an instance:
A static member is shared by all objects of the class, all static data is initialized to zero when the first object is created if no other initialization is present, And constructor and static member function can only access static data member, other static member functions and any other functions from outside the class.
In C++, you can do it with a template base class. Basically it is a mixin, so it does still require each class to co-operate by inheriting from the mixin:
// warning: not thread-safe
template <typename T>
class instance_counter {
public:
static size_t InstancesCount() { return count(); }
instance_counter() { count() += 1; }
instance_counter(const instance_counter&) { count() += 1; }
// rare case where we don't need to implement the copy assignment operator.
protected:
~instance_counter() { count() -= 1; }
private:
static size_t &count {
static size_t counter = 0;
return counter;
}
};
class my_class: public instance_counter<my_class> {};
Since each class using the template has a different base class, it has a different count
function and hence a different copy of the static variable counter
.
The trick of inheriting from a template class that's instantiated using the derived class as a template parameter is called CRTP.
In Java you can use a global Multiset
:
import com.google.common.collect.ConcurrentHashMultiset;
public abstract class InstanceCounted {
protected InstanceCounted() {
COUNT_MAP.add(this.getClass());
}
protected static final ConcurrentHashMultiset<Class<? extends InstanceCounted>> COUNT_MAP =
ConcurrentHashMultiset.create();
}
Alternatively you can use a Map<Class, Integer>
if you don't want the dependency on guava.
Note: this only tracks instance creation, not garbage collection, so the count will never decrease. You can also track collection using PhantomReference
s if you are willing to take a performance hit:
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
public abstract class InstanceCounted {
public static int getInstanceCount(Class<? extends InstanceCounted> clazz) {
reap();
return INSTANCES.get(clazz).size();
}
protected InstanceCounted() {
reap();
INSTANCES.put(getClass(), new CountingReference(this));
}
static final Multimap<Class<? extends InstanceCounted>, CountingReference> INSTANCES =
Multimaps.synchronizedSetMultimap(HashMultimap.<Class<? extends InstanceCounted>, CountingReference>create());
static final ReferenceQueue<InstanceCounted> QUEUE =
new ReferenceQueue<InstanceCounted>();
private static void reap() {
Reference<? extends InstanceCounted> ref;
while ((ref = QUEUE.poll()) != null) {
((CountingReference) ref).clear();
}
}
private static class CountingReference extends PhantomReference<InstanceCounted> {
public void clear() {
super.clear();
INSTANCES.remove(clazz, this);
}
CountingReference(InstanceCounted instance) {
super(instance, QUEUE);
this.clazz = instance.getClass();
}
private final Class<? extends InstanceCounted> clazz;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With