我需要跟踪特定类创建的所有对象,我需要使用标识符字符串来访问它们。以下代码几乎完全符合我的需要。 NamedObject类有一个静态成员m_object_by_name,它将名称(字符串)映射到对象,构造函数将每个创建的对象添加到地图中,析构函数从地图中删除已删除的对象。
#include <map>
#include <string>
#include <iostream>
using namespace std;
class NamedObject
{
public:
static NamedObject *object_by_name(const string &name) {
return m_object_by_name[name];
}
NamedObject(const string &name) : m_name(name) {
m_object_by_name[m_name] = this;
}
~NamedObject() {
m_object_by_name.erase(this->m_name);
}
const string &name() const{
return m_name;
}
private:
string m_name;
static map<string, NamedObject *> m_object_by_name;
};
map<string, NamedObject *> NamedObject::m_object_by_name;
int main ()
{
new NamedObject("name1");
new NamedObject("name2");
NamedObject *obj1 = NamedObject::object_by_name("name1");
NamedObject *obj2 = NamedObject::object_by_name("name2");
cout << obj1->name() << endl;
cout << obj2->name() << endl;
}
现在我有几个类,其对象需要通过名称访问。继承上面的NamedObject类当然会遇到这样的问题:所有这些类都会共享它们的名称(例如,我不能拥有两个不同类但具有相同名称的对象),因为它们共享映射m_objects_by_name。此外,当使用object_by_name()方法访问对象时,我总是必须从NamedObject强制转换为实际的类。
我目前使用的此问题的解决方案可以在以下代码中看到。但是,我对这个解决方案并不满意(见下面的评论)。模板类NamedObjectStore现在负责存储类T的所有对象。此外,还有一个基类处理具有名称和实际使用的派生类的属性。派生类有一个静态NamedObjectStore对象,它在创建时添加其对象,并在删除时删除它们。
#include <map>
#include <string>
#include <iostream>
using namespace std;
template <class T>
class NamedObjectStore
{
public:
void add_object(T *obj) {
m_object_by_name[obj->name()] = obj;
}
void rem_object(T *obj) {
m_object_by_name.erase(obj->name());
}
T *object_by_name(const string &name) {
return m_object_by_name[name];
}
private:
map<string, T *> m_object_by_name;
};
class BaseNamedObject
{
public:
BaseNamedObject(const string &name) : m_name(name) {
}
const string &name() const {
return m_name;
}
private:
string m_name;
};
class DerivedNamedObject : public BaseNamedObject
{
public:
static NamedObjectStore<DerivedNamedObject> store;
DerivedNamedObject(const string &name) : BaseNamedObject(name) {
store.add_object(this);
}
~DerivedNamedObject() {
store.rem_object(this);
}
};
NamedObjectStore<DerivedNamedObject> DerivedNamedObject::store;
int main ()
{
new DerivedNamedObject("name1");
new DerivedNamedObject("name2");
DerivedNamedObject *obj1 = DerivedNamedObject::store.object_by_name("name1");
DerivedNamedObject *obj2 = DerivedNamedObject::store.object_by_name("name2");
cout << obj1->name() << endl;
cout << obj2->name() << endl;
}
从积极的方面来说,使对象成为命名对象(即name() - function)的实现是在基类BaseNamedObject中完成的。存储所有对象的结构的实现也位于NamedObjectStore类中,并隐藏在其方法后面。这允许我根据需要轻松更改这两个实现,而无需触及所有派生类。
从消极方面来说,我仍然需要一遍又一遍地输入相同的东西。更确切地说,对于每个派生类(如DerivedNamedObject),我必须声明并定义静态成员存储,我必须在构造函数中将对象添加到存储中,并将它们从析构函数中的存储中删除。
所以这就是我的问题:有没有更好的方法来解决这个问题?或者我只需要在每个派生类中使用这四行代码?
希望得到一些鼓舞人心的建议: - )
托马斯
答案 0 :(得分:2)
如我的评论中所述,您可以使用curiously recurring template pattern解决此问题。下面的代码使用您的原始示例,模板实际存储的类型:
#include <map>
#include <string>
#include <iostream>
using namespace std;
template<class T>
class NamedObject
{
public:
static NamedObject *object_by_name(const string &name) {
return m_object_by_name[name];
}
NamedObject(const string &name) : m_name(name) {
m_object_by_name[m_name] = this;
}
virtual ~NamedObject() {
m_object_by_name.erase(this->m_name);
}
const string &name() const{
return m_name;
}
private:
string m_name;
static map<string, NamedObject *> m_object_by_name;
};
template <class T>
map<string, NamedObject<T> *> NamedObject<T>::m_object_by_name;
class A : public NamedObject<A>
{
public:
A(const std::string& name) : NamedObject(name)
{}
};
class B : public NamedObject<B>
{
public:
B(const std::string& name) : NamedObject(name)
{}
};
int main()
{
new A("Test");
new B("Test");
auto one = A::object_by_name("Test");
auto two = B::object_by_name("Test");
cout << one << " - " << one->name() << "\n";
cout << two << " - " << two->name() << "\n";
delete two;
delete one;
}