计算每个派生类的类实例

有没有办法让所有派生类计算他们的实例?如何(用C ++,C#,Java之一编写代码)?

想象一下,我可以访问根类(例如对象),并且每个其他类(直接或间接)都是从这个类派生的。 我想要的是:

AnyDerivedClass.InstancesCount() 

问题是,必须跟踪静态变量中的计数,但是不可能将静态变量“注入”到基类的派生类中,这仅适用于成员变量。 也就是说,我必须写下这样的东西:

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

这个function显然是重复的,我不能把它放在基类中。 注意有两种计算方法:如果有7个类的derived1实例和8个类的derived2实例,则有(a)15个对象实例或(b)0个对象实例。 我不关心哪一个,因为我不能做任何事(使用合理的实用手段,例如想象100个类,其中一半是在库中我无法修改)。

当然,理论上可以创建(某些运行类型类型标识符)=> int count的映射,并使用基于丑陋,慢,(运行时类型)的方法(至少在C#,Java中)。

当然,如果我可以修改派生类,我可以使用复制粘贴(可怕),宏(是的,我知道),mixins(不是这些语言)等。但这仍然是真正的丑陋。

这是具体的问题,但它发生在我身上好几次,我希望能够将静态成员“注入”派生类来优雅地解决问题。

非常感谢。

编辑:谢谢你的好答案,在C ++中它也可能使用CRTP(奇怪的重复模板模式),但不能用于C#/ Java(没有多重inheritance)。 当然,必须有权访问派生类并添加这个基类,所以问题仍然存在(如果没有其他方法,这看起来最好)。

编辑2:使用当前语言看起来不可能。 每个类的静态部分都不是inheritance(并且这是正确的),但是没有与每个类关联的inheritance单例,因此这些问题不能如此优雅地解决。 为了说明这一点,请看下面的代码:普通成员和静态成员是当前的OOP语言function,“singleton”(或者任何单词)成员是我的建议/愿望:

 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; 

如果语言中出现类似的内容,我的问题的解决方案将简单而优雅:

 //with singleton members, I could write counter like this: class object { singleton int count; object() { ++count; } ~object() { --count; } }; 

在C ++中,您可以使用模板基类来完成它。 基本上它一个mixin,所以它仍然需要每个类通过inheritancemixin来合作:

 // warning: not thread-safe template  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 {}; 

由于使用模板的每个类具有不同的基类,因此它具有不同的 count函数,因此具有静态变量counter的不同副本。

从使用派生类作为模板参数实例化的模板类inheritance的技巧称为CRTP。

在Java中,您可以使用全局Multiset

 import com.google.common.collect.ConcurrentHashMultiset; public abstract class InstanceCounted { protected InstanceCounted() { COUNT_MAP.add(this.getClass()); } protected static final ConcurrentHashMultiset> COUNT_MAP = ConcurrentHashMultiset.create(); } 

或者Map如果您不希望依赖于番石榴Map可以使用Map

注意:这只跟踪实例创建 ,而不是垃圾回收,因此计数永远不会减少。 如果您愿意接受性能影响,也可以使用PhantomReference跟踪收集:

 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 clazz) { reap(); return INSTANCES.get(clazz).size(); } protected InstanceCounted() { reap(); INSTANCES.put(getClass(), new CountingReference(this)); } static final Multimap, CountingReference> INSTANCES = Multimaps.synchronizedSetMultimap(HashMultimap., CountingReference>create()); static final ReferenceQueue QUEUE = new ReferenceQueue(); private static void reap() { Reference ref; while ((ref = QUEUE.poll()) != null) { ((CountingReference) ref).clear(); } } private static class CountingReference extends PhantomReference { public void clear() { super.clear(); INSTANCES.remove(clazz, this); } CountingReference(InstanceCounted instance) { super(instance, QUEUE); this.clazz = instance.getClass(); } private final Class clazz; } } 

在Java中,您可以将计数function实现到hirachy的常见超类中。

此基类包含一个Map – 将类与实例数相关联。 如果创建了base的实例或其子类之一,则调用构造函数。 构造函数增加了concreate类的实例数。

 import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; public class Base { /** Threadsave counter */ private static final ConcurrentMap, AtomicInteger> instancesByClass = new ConcurrentHashMap, AtomicInteger>( 10); /** The only one constructor of base */ public Base() { Class concreateClass = this.getClass(); AtomicInteger oldValue = instancesByClass.putIfAbsent(concreateClass, new AtomicInteger(1)); if (oldValue != null) { oldValue.incrementAndGet(); } } /* DEMO starts here */ public static class SubA extends Base{ } public static class SubB extends Base{ } public static class SubSubA extends SubA{ } public static void main(String[] args) { printNumbers(); new SubA(); new SubA(); new SubB(); new SubSubA(); printNumbers(); } private static void printNumbers() { // not thread save! for (Entry, AtomicInteger> item : instancesByClass .entrySet()) { System.out.println(item.getKey().getName() + " : " + item.getValue()); } } } 

我会用一个模板。 顺便说一下,这是用C ++编写的。

 template class object { private: static int count; public: object() { count++; } object(const object&) { count++; } ~object() { count--; } static int GetCount() { return count; } }; template int object::count = 0; 

RTTI解决方案:

 class object { static std::map counts; public: object() { counts[typeid(*this).name()]++; } object(const object&) { counts[typeid(*this).name()]++; } ~object() { counts[typeid(*this).name()]--; } template int GetObjectsOfType() { return counts[typeid(T).name()]; } int GetObjectsOfType(std::string type) { return counts[type]; } }; std::map object::counts; 

RTTI的入侵性较小,允许对要查询的类型进行运行时选择,但模板的开销要小得多,您可以使用它来单独计算每个派生类,而RTTI只能单独计算最多的派生类。

令我感到震惊的是,如果你真的希望注入/任何类实际上做一些有用的东西,那么你必须以某种方式将它与原始类耦合,无论是inheritance还是与方法调用的直接耦合。 否则你只有两个轮子独立旋转。

我能想到的唯一选择是使用可以为你计算创造的工厂模式 – 但是你必须通过破解来计算减量,比如将对象明确地交给工厂。

在C#中的方式立即出现在我的脑海中:

 class A : IDisposable { static Dictionary _typeCounts = new Dictionary(); private bool _disposed = false; public static int GetCount() where T:A { if (!_typeCounts.ContainsKey(typeof(T))) return 0; return _typeCounts[typeof(T)]; } public A() { Increment(); } private void Increment() { var type = this.GetType(); if (!_typeCounts.ContainsKey(type)) _typeCounts[type] = 0; _typeCounts[type]++; } private void Decrement() { var type = this.GetType(); _typeCounts[type]--; } ~A() { if (!_disposed) Decrement(); } public void Dispose() { _disposed = true; Decrement(); } } class B : A { } 

以及如何使用它:

  A a1 = new A(); Console.WriteLine(A.GetCount()); A a2 = new A(); Console.WriteLine(A.GetCount()); using(B b1 = new B()) { Console.WriteLine(B.GetCount()); } Console.WriteLine(B.GetCount()); 

可能会以不同的方式完成输出。 它不是纯粹的OOP,但也不是这个线程中的C ++或Java示例。 但它在inheritance类时不需要一些代码。

并且不要忘记正确处理你的物品!

在.Net中,可以使用generics来实现此目的。 由于类型擦除 ,以下技术在Java中不起作用。

 public static class InstanceCounter { private static int _counter; public static int Count { get { return _counter; }} public static void Increase() { _counter++; } public static void Decrease() { _counter--; } } 

现在在您的类中,无论是基类还是子类,请按如下方式使用它:

 public class SomeClass { public SomeClass() { InstanceCounter.Increase(); } ~SomeClass() { InstanceCounter.Decrease(); } } 

您不必在每个类中都包含实例计数属性,只需要在InstanceCounter类中使用它。

 int someClassCount = InstanceCounter.Count; 

注意 :此示例不要求类inheritance实例计数器类。

如果有人能够在.Net中烧掉一个超类限制,那么以下内容也可以:

 public class InstanceCounter { private static int _counter; public static int Count { get { return _counter; }} protected InstanceCounter() { _counter++; } ~InstanceCounter() { _counter--; } } public class SomeClass : InstanceCounter { } 

然后检索计数:

 int someClassCount = InstanceCounter.Count; 

要么

 int someClassCount = SomeClass.Count; 

注意2 :如评论中所述,使用终结器( ~SomeClass )很慢,并且只有在GC实际收集实例时才会减少计数器。 为了解决这个问题,必须引入确定性的“释放”实例,例如实现IDisposable