我创建了一个基类对象来跟踪某些对象的实例。我想在这样的文件中记录它:
Object Name: Number of instances
这是我的基类:
template <class T>
class CountedObj
{
public:
CountedObj()
{
// write name of derived class and counter to log
}
CountedObj(const CountedObj& obj)
{
// write name of derived class and counter to log
}
~CountedObj()
{
// write name of derived class and counter to log
}
private:
int counter;
mylogger log;
};
我的问题是我要打印将继承自CountedObj
的类的名称,但我不能在构造函数中使用typeid
。
是否有任何替代方法可以记录分配和取消分配哪个对象?
答案 0 :(得分:1)
您没有指定如何使用此CountedObj
。我假设这个:
class Foo: public CountedObj<Foo> {
};
如果从Foo
进一步派生,那么你的计数器已经无法区分Foo及其派生类,所以我想你要打印“Foo”作为所有派生类的名称。如果你想区分这些类,那么需要一个不同的解决方案(如果是这样的话我会删除这个答案)。
(或者您可以从CountedObj
class FooDerived: public Foo, public CountedObj<FooDerived> { };
再次获得,但这样,FooDerived
将被计为FooDerived
和Foo
)< / p>
所以,可以以这种方式使用typeid:
template <typename T>
class CountedObj {
public:
CountedObj() {
counter++;
printf("%s: %d\n", typeid(T).name(), counter);
}
private:
static int counter; // static is needed
};
如果您不喜欢typeid().name()
的输出,那么您可以在Foo中添加静态名称查询功能:
template <typename T>
class CountedObj {
public:
CountedObj() {
counter++;
printf("%s: %d\n", T::name(), counter);
}
...
};
class Foo: public CountedObj<Foo> {
public:
static const char *name() {
return "Foo";
}
};
答案 1 :(得分:0)
编辑:这是一个更好更清洁的版本
解决方案是在 CountedObj 中使用unordered_map。这是类名称和实例数之间的关联映射。
然后对于每个类,存储CountedObj并增加unordered_map中的实例数。
#include <stdio.h>
#include <iostream>
#include <string>
#include <unordered_map>
class CountedObj
{
public:
void increase_instance(const std::string& s)
{
if (instances.find(s) == instances.end())
instances[s] = 1;
else
instances[s] += 1;
}
void pretty_print()
{
for(auto& n = instances.begin(); n != instances.end(); ++n)
std::cout << "Name of the class " << n->first << " : instances =>" << n->second << std::endl;
}
private:
std::unordered_map<std::string, unsigned int> instances;
};
class A
{
public:
A(CountedObj& o)
: name("A"),
obj(o)
{
o.increase_instance(name);
}
const std::string& name;
private:
CountedObj& obj;
};
class B
{
public:
B(CountedObj& o)
: name("B"),
obj(o)
{
o.increase_instance(name);
}
const std::string& name;
private:
CountedObj& obj;
};
int main()
{
CountedObj c;
A a(c), aa(c), aaa(c);
B b(c), bb(c);
c.pretty_print();
return 0;
}
节目输出
Name of the class A : instances =>3
Name of the class B : instances =>2
如果您不想在每个班级中存储CounterObj,您可以将CounterObj类定义为Singleton。
======
我创建了一个基类对象来跟踪某些对象的实例。
您是否认为您要跟踪的对象是相关的? (例如,基类A有几个孩子,如B和C)。如果你想跟踪不同的实例,最好有一个唯一的类型来存储对象(比如在A的向量中)。
要跟踪每个类的实例数,需要为每个可跟踪类存储一个静态int(类变量)。
在每个构造函数中,将此变量增加1。
#include <iostream>
#include <vector>
#include <string>
class A
{
public:
A(const std::string& n) : name("A")
{
instance_num += 1;
name = n;
}
std::string toString()
{
return name;
}
virtual int instance_num_get()
{
return instance_num;
}
static int instance_num;
protected:
std::string name;
};
class B : public A
{
public:
B()
: A("B")
{
instance_num += 1;
}
int instance_num_get()
{
return instance_num;
}
static int instance_num;
};
class C : public A
{
public:
C()
: A("C")
{
instance_num += 1;
}
int instance_num_get()
{
return instance_num;
}
static int instance_num;
};
对于 CountedObj ,我使用了一个A *向量,其中包含每个类的一个实例(我们只需要一个来访问不同的类变量)。
template<typename T>
class CountedObj
{
public:
CountedObj(std::vector<T*>& v)
: obj_list(v)
{
}
void pretty_print()
{
for (auto elt = obj_list.begin(); elt != obj_list.end(); ++elt)
std::cout << (*elt)->toString() << ": " << (*elt)->instance_num_get() << std::endl;
}
private:
std::vector<T*> obj_list;
};
使用 pretty_print 方法,我们显示类的名称和实例化的数量。
我们初始化类变量。这是一个有效的例子:
int A::instance_num = 0;
int B::instance_num = 0;
int C::instance_num = 0;
int main(void)
{
A a("A");
B b;
C c;
std::vector<A*> vec;
vec.push_back(&a);
vec.push_back(&b);
vec.push_back(&c);
CountedObj<A> count(vec);
count.pretty_print();
return 0;
}
将给出
Output:
A: 3
B: 1
C: 1
我认为使用Observer design pattern会很有趣,这是我提供的解决方案中的想法