You can use virtual inheritance to force the counting base class constructor to be called by every super class constructor and only that constructor. This fixes the double counting problem. Then use RTTI for the rest:
#include <map>
#include <typeinfo>
#include <iostream>
struct type_info_less
{
bool operator() (const std::type_info * t1, const std::type_info * t2) {
return t1->before(*t2);
}
};
struct InstCounter
{
typedef std::map<const std::type_info *, size_t, type_info_less> CountMap;
static CountMap countMap_;
const std::type_info * my_type_;
InstCounter(const std::type_info & type) : my_type_(&type){
++countMap_[my_type_];
}
~InstCounter() {
--countMap_[my_type_];
}
static size_t getCount(const std::type_info & type) {
return countMap_[&type];
}
size_t getCount() {
return countMap_[my_type_];
}
};
InstCounter::CountMap InstCounter::countMap_;
struct A : public virtual InstCounter
{
A() : InstCounter(typeid(A)) {}
};
struct B : public A
{
B() : InstCounter(typeid(B)) {}
};
struct C : public B
{
C() : InstCounter(typeid(C)) {}
};
int main(int argc, char * argv[])
{
std::cout << "A: " << InstCounter::getCount(typeid(A)) << std::endl;
std::cout << "B: " << InstCounter::getCount(typeid(B)) << std::endl;
std::cout << "C: " << InstCounter::getCount(typeid(B)) << std::endl;
{
A a1, a2, a3;
B b1;
C c1, c2;
std::cout << "A: " << InstCounter::getCount(typeid(A)) << std::endl;
std::cout << "A: " << a1.getCount() << std::endl;
std::cout << "B: " << InstCounter::getCount(typeid(B)) << std::endl;
std::cout << "B: " << b1.getCount() << std::endl;
std::cout << "C: " << InstCounter::getCount(typeid(C)) << std::endl;
std::cout << "C: " << c1.getCount() << std::endl;
}
std::cout << "A: " << InstCounter::getCount(typeid(A)) << std::endl;
std::cout << "B: " << InstCounter::getCount(typeid(B)) << std::endl;
std::cout << "C: " << InstCounter::getCount(typeid(C)) << std::endl;
return 0;
}
This results in
A: 0
B: 0
C: 0
A: 3
A: 3
B: 1
B: 1
C: 2
C: 2
A: 0
B: 0
C: 0
Unfortunately you must store the type for each instance as calling typeid(*this) in InstCounter::getCount() returns the type_info for InstCounter and not the most derived type. (At least with VS2005)
NOTE: Each constructor for A, B and C have to call the InstCounter constructor explicitly then pass their typeid in. There is a down side to this, if you copy and paste this code for each new sub class you can forget to change the parameter to typeid.
Updated to add decrementing destructor.