2013-11-25 65 views
0

我需要跟蹤爲特定類創建的所有對象,並且需要使用標識符字符串來訪問它們。以下代碼幾乎完全符合我的需求。 NamedObject類具有靜態成員m_object_by_name,它將名稱(字符串)映射到對象,構造函數將每個創建的對象添加到地圖,析構函數從地圖中刪除已刪除的對象。C++:跟蹤所有現有的對象

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

從積極的一面,是什麼使對象的命名對象的實現(即名稱() - 函數)在基類BaseNamedObject完成。存儲所有對象的結構的實現位於NamedObjectStore類中,並隱藏在其方法後面。這使我可以根據需要輕鬆更改這兩個實現,而無需觸及所有派生類。

在消極的一面,我仍然需要反覆輸入相同的東西。更確切地說,對於每個派生類(比如DerivedNamedObject),我必須聲明並定義靜態成員存儲,我必須在構造函數中將商店對象添加到商店中,並在析構函數中將其從商店中移除。

因此,我的問題是:是否有更好的方法來解決這個問題?或者我只需要在每個派生類中使用這四行代碼?

希望能對一些鼓舞人心的建議:-)

托馬斯

+1

http://codereview.stackexchange.com/可能是一個更好的地方。 – crashmstr

+0

聽起來像http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern就足夠了 – Chad

+0

如果你要從NamedObject繼承,應該有一個虛擬析構函數。 –

回答

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

+1,但析構函數應該是虛擬的。 –