计算各个派生类的实例

时间:2009-04-21 13:43:28

标签: c++

我希望能够计算属于同一个类层次结构的类的实例。

例如,假设我有这个:

class A;
class B: public A;
class C: public B;

然后我有了这段代码

A* tempA = new A;
B* tempB = new B;
C* tempC = new C;
C* tempC2 = new C;

printf(tempA->GetInstancesCount());
printf(tempB->GetInstancesCount());
printf(tempC->GetInstancesCount());

结果应该打印
    1
    1
    2个

理想情况下,计数应该在内部完成。每个类,而不是某种经理,应该知道它有多少个实例。

有什么想法吗?

谢谢!

10 个答案:

答案 0 :(得分:6)

建议的解决方案存在问题:当您创建B时,您将自动调用构造函数,从而增加A的计数。

class A
{
public:
    A(bool doCount = true)
    {
        if (doCount)
            ++instanceCount_;
    }

    static std::size_t GetInstanceCount()
    {
        return instanceCount_;
    }

    virtual ~A(){}
private:
    static std::size_t instanceCount_;
};

class B: public A
{
public:
    B(bool doCount = true):A(false)
    {
        if (doCount)
            ++instanceCount_;
    }

    static std::size_t GetInstanceCount()
    {
        return instanceCount_;
    }
private:
    static std::size_t instanceCount_;
};

std::size_t A::instanceCount_ = 0;
std::size_t B::instanceCount_ = 0;

答案 1 :(得分:4)

直接离开我的脑袋:

  • 在中创建一个整数静态字段 每节课。注意整数溢出。
  • 将其初始化为0 emulated static constructor
  • 每个增加(非静态) 构造函数体。在减少它 析构函数。
  • GetInstancesCount()是一个静态函数,它返回整数静态字段的值。

注意:请参阅Mykola的评论。这将打印4为A,3为B,2为C,即它将B的一个实例计为“一个A和一个B”,一个C为“一个A,一个B和一个C”。这在某种程度上是正确的,但不是问题所要求的。换句话说,我的回答是错误的:)

答案 2 :(得分:3)

一些“奇怪的重复发生的模板模式”。

template<typename P>
class Counter
{
    public: Counter(bool inc)
        :m_wasInc(inc)
    {
        if (m_wasInc)
        {   getCount()++;}
    }
           ~Counter()
    {
        if (m_wasInc)
        {   getCount()--;}
    }
    static std::size_t GetInstancesCount()
    {
         return getCount();
    }
    private:
       bool m_wasInc;
       /*
        * Alternatively this can be a static member variable.
        * I just used a function because this means I do not need to declare
        * the variable for each type class. The down size is that it becomes
        * more complex if used in the presence of a DLL's.
        *
        * But that is way easy to change. See Alternative Version below.
        */
       static std::size_t& getCount()
       {
           static std::size_t count = 0;
           return count;
       }
};

class A: public Counter<A>
{
    public: A(bool count = true): Counter<A>(count){}
};

class B: public A,Counter<B>
{
    public: B(bool count = true): A(false), Counter<B>(count){}
};

class C: public A, Counter<C>
{
    public: C(bool count = true): A(false), Counter<C>(count){}
};

template<typename P>
class CounterAlt
{
    public: CounterAlt()
    {    ++count;
    }
    static std::size_t GetInstancesCount()
    {
         return count;
    }
    private:
       static std::size_t count;
};

class D: public CounterAlt<D>
{
};
std::size_t CounterAlt<D>::count = 0;

答案 3 :(得分:2)

为每个类使用static成员变量。

struct A {
    A() { mInstances++; }
    ~A() { mInstances--; }
    static size_t mInstances;
    static size_t GetInstancesCount() { return mInstances; }
};

size_t A::mInstances;

int main() {
    A* a = new A;
    A* aa = new A;
    cout << A::GetInstancesCount() << endl;
    delete a;
    delete aa;
    cout << A::GetInstancesCount() << endl;
    return 0;
}

答案 4 :(得分:1)

非常粗暴的方式是:

class A
{
public:
    static int m_instanceCount;
    A(bool derivedInstance = false)
    {
        if(! derivedInstance)
        {
            ++m_instanceCount;
        }
    }
    virtual ~A()
    {
        --m_instanceCount;
    }
    virtual int GetInstanceCount()
    {
        return m_instanceCount;
    }
};

int A::m_instanceCount = 0;


class B : public A
{
public:
    static int m_instanceCount;
    B(bool derivedInstance = false): A(true) 
    {
        if(! derivedInstance)
        {
            ++m_instanceCount;
        }
    }
    virtual ~B()
    {
        --m_instanceCount;
    }
    virtual int GetInstanceCount()
    {
        return m_instanceCount;
    }
};

int B::m_instanceCount = 0;


class C : public B
{
public:
    static int m_instanceCount;
    C(): B(true) {++m_instanceCount;}
    virtual ~C()
    {
        --m_instanceCount;
    }
    virtual int GetInstanceCount()
    {
        return m_instanceCount;
    }
};

int C::m_instanceCount = 0;




void main(int argc,char *argv[])
{   
    A* p1 = new A;
    B* p2 = new B;
    C* p3 = new C;
    C* p4 = new C;
    A* p5 = new A;

    delete p5;

    std::cout<<p1->GetInstanceCount()<<"\n";
    std::cout<<p2->GetInstanceCount()<<"\n";
    std::cout<<p3->GetInstanceCount()<<"\n";
}   

答案 5 :(得分:1)

这是一个简单的计数器,我经常使用它们进行调试:

// counter.hpp
#ifndef COUNTER_HPP
#define COUNTER_HPP

template <typename T>
class Counter
{
public:
    Counter( bool do_count = true ) : counted(do_count) 
    { if ( counted ) get_count()++; }
    ~Counter() { if (counted) --count_; }

    static unsigned long count() { return count_; }
    static unsigned long& get_count() { 
       static unsigned long count=0;
       return count;
    }
private:
    bool do_count;
};
#endif 

用法很简单,只需继承它:

class BaseClass : public Counter<BaseClass>
{
public:
   explicit BaseClass( bool do_count = true ) 
      : Counter<BaseClass>( do_count )
   {}
};
class DerivedClass : public BaseClass, Counter<DerivedClass>
{
public:
   explicit DerivedClass( bool do_count = true )
      : BaseClass(false), Counter<DerivedClass>(do_count)
   {}
};

用户代码将调用无参数构造函数:

int main() {
   BaseClass b; // will call Counter<BaseClass>(true)
   DerivedClass d; // will call Counter<BaseClass>(false), Counter<DerivedClass>(true)
}

答案 6 :(得分:1)

在构造函数中计算对象时,绕过重复计算的一种方法是使用RTTI计算需要点的对象,而不是在构造函数中。这是极少侵入性的:

#include <vector>
#include <typeinfo>
#include <iostream>
#include <functional>


class A
{

public:

    A();
    virtual ~A() { }

};

class B: public A
{

public:

    virtual ~B() { }
};

class C: public B
{

public:

    virtual ~C() { }

};

template<class T>
struct TypeIdsEqual: public std::binary_function<T, T, bool>
{
    bool operator() (const T& obj1, const T& obj2) const
    {
        return typeid(*obj1) == typeid(*obj2);
    }
};

struct Counter
{
    static std::vector<A*> objects;

    static void add(A* obj)
    {
        objects.push_back(obj);
    }

    static int count(A* obj)
    {
        return std::count_if(objects.begin(), objects.end(),
                             std::bind1st(TypeIdsEqual<A*>(), obj));
    }

};

std::vector<A*> Counter::objects;

// One intrusive line in the base class constructor.  None in derived classes...
A::A()
{
    Counter::add(this);
}

int main(int *argc, char* argv[])
{
    A* a  = new A;
    B* b  = new B;
    C* c  = new C;
    C* c2 = new C;
    std::cout << Counter::count(*a) << std::endl;  // Output: 1
    std::cout << Counter::count(*b) << std::endl;  // Output: 1
    std::cout << Counter::count(*c) << std::endl;  // Output: 2
}

答案 7 :(得分:0)

通过工厂创建类,以便工厂能够跟踪已创建的数量。

不像在课堂上调用新课程那样干净,但它可能会做你需要的。

答案 8 :(得分:0)

当前的解决方案似乎都在构造函数中计算,因此也算在基类型的构造函数中。 (除了Mykola,但是这个解决方案有一个隐含的转换来自bool - 坏)这种重复计算是不可取的。但是,棘手的部分是构造派生类型时,对象临时具有中间基类型。对于虚拟基类,这种情况更糟。在这种情况下,中间类型甚至没有明确定义。

忽略这种瞬变,有一些重复计算的解决方案:

  • 使用标志禁用计数
  • 使用不计数的受保护基类构造函数
  • 减少派生构造函数中的基类的实例数*(this-&gt; base :: count) - `
  • 将计数保留在专用的虚拟基类中。

后一种选择(虚拟基类)可能是最好的;编译器将强制它从最终的ctor中初始化一次且仅一次。

class counter {
    template<typename T> struct perTypeCounter { static int count =  0; }
    int* count; // Points to perTypeCounter<MostDerived>::count

    protected:
    template<typename MostDerived> counter(MostDerived*) 
    {
        count = &perTypeCounter<MostDerived>::count;
        ++*count;
    }
    ~counter() { --*count; }
};

答案 9 :(得分:0)

您可以使用虚拟继承来强制计数基类构造函数由每个超类构造函数和仅该构造函数调用。这解决了重复计算问题。然后使用RTTI进行其余的工作:

#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;
}

这导致

A: 0
B: 0
C: 0
A: 3
A: 3
B: 1
B: 1
C: 2
C: 2
A: 0
B: 0
C: 0

不幸的是,您必须存储每个实例的类型,因为在InstCounter :: getCount()中调用typeid(* this)会返回InstCounter的type_info,而不是最派生的类型。 (至少VS2005)

注意:A,B和C的每个构造函数都必须显式调用InstCounter构造函数然后传递它们的typeid。如果你为每个新的子类复制并粘贴这个代码,你可以忘记将参数更改为typeid。

更新以添加递减的析构函数。