2013-08-06 77 views
7

我有一個對象,這個對象中的每個成員變量都有一個名稱,我可以通過調用get_name()來獲得它,我想要做的是連接所有的名稱按字母順序排列成員變量,然後做一些事情。例如:函數代替複製粘貼編程

class CXMLWrapper<class T> 
{ 
public: 
    CXMLWrapper(const char* p_name) : m_local_name(p_name) 
    { 
    } 
    //skip the get_name(), set_name() and others  
private: 
    string m_local_name; 
    T m_type_var; 
} 
class object 
{ 
public: 
    object() : m_team("team"), m_base("base") 
    { 
    } 
public: 
    CXMLWrapper<string> m_team; 
    CXMLWrapper<string> m_base; 
... 
} 

我不得不硬代碼:

object o; 
string sign = o.m_base.get_name(); 
sign += o.m_team.get_name(); 

我需要一個函數來做到這一點,而不是複製和粘貼時,對象不同而不同。任何人有想法?

+0

你有各種各樣的成員變量的對象嗎? – doctorlove

+2

也許你可以使用一些這個集合?也許矢量。例如:class object {/*....*/ vector > some_vars /*....*/} /*....*/ for(auto&it:o.some_vars {sign + = it。 get_name;})或者可能是字典/地圖 –

+1

它不是一個函數和更多*反射*。有一些方法可以在C++中提供某種程度的反思,但如果沒有它,那麼最好。 –

回答

2

在普通C++中做到這一點的一種方式,只要所有成員屬於同一個類或從某個基類派生,都將使用可變數量的參數。一個例子如下。

#include <stdarg.h> 
string concatenateNames(int numMembers, ...) 
{ 
    string output; 
    va_list args; 
    va_start(args, numMembers); 
    for(int i = 0; i < numMembers; i++) 
    { 
     MemberClass *pMember = va_arg(args, MemberClass*); 
     output += pMember->get_name(); 
    } 
    va_end(args); 
    return output; 
} 

class Object 
{ 
    public: 
     MemberClass x; 
     MemberClass y; 
     MemberClass z; 
}; 

int main() 
{ 
    Object o; 
    string sign = concatenateNames(3, &o.x, &o.y, &o.z); 
} 

如果類型的所有成員都是不同的,你可以看看的C++ 11X可變參數模板:http://en.wikipedia.org/wiki/Variadic_Templates,但我似乎無法找到一個辦法不這樣做。

+0

雖然這不是一個完美的解決方案,但它可以刪除大量重複的代碼。我可以使用矢量在for循環中保存字符串,並按字母順序對它們進行排序,然後連接。謝謝! – jfly

-2

這看起來像一個「觀察者模式」,你只需要保持一個副本對象作爲成員變量「串名_;」,並通過name_s的引用到CXMLWrapper這樣的:

class CXMLWrapper<class T> 
{ 
public: 
    CXMLWrapper(const string &name) 
     : local_name_(name) 
     { 
     } 
    //skip the get_name() set_name()  
    private: 
     const string &local_name_; 
} 

class object 
{ 
public: 
    object() 
     : team_("team"), 
      base_("base"), 
      m_team(team_) 
     , m_base(base_) 
     { 
     } 
public: 
    string team_; 
    string base_; 
    CXMLWrapper<string> m_team; 
    CXMLWrapper<string> m_base; 
} 
+0

你的代碼**很**危險,在它正常的情況下不可用。你使用引用,所以不能分配'CXMLWrapper'和'obejct'。 –

+1

我沒有在那裏看到一個觀察者模式 – doctorlove

+0

@JanHerrmann我沒有看到危險,我不清楚你的意思是「不能分配」 - 你在談論三/五/零規則? – doctorlove

0

如果具有名稱的變量具有相同的類型(或者這些類型屬於一個層次結構),則可以使用這些變量的映射。是不是好辦法,但也許它可以幫助你

class object 
{ 
public: 
    object() //: m_team("team"), m_base("base") 
    { 
     this->vars["m_team"] = CXMLWrapper<string>("team"); 
     //..... 
    } 
public: 
    map<string, CXMLWrapper<string> > vars; 
    /*CXMLWrapper<string> m_team; 
    CXMLWrapper<string> m_base;*/ 
... 
} 

object o; 
string sign; 
for(auto& x : o.vars)//i cannot remember syntax of for of map 
    sign += x.get_name; 

PS對不起,我犯的錯誤。英語不是我的母語。

+1

使用此代碼將執行字符串型編碼。您可能希望將成員變量當作實際的成員變量,而不僅僅是正常使用的名稱隱藏在地圖中 – doctorlove

+0

@Dark_Daiver感謝您的建議,但我無法更改對象的佈局,因爲它是傳遞給我的參數。 – jfly

0

一種方法是讓成員名稱的外部庫,它的CXMLWrapper類更新: -

class BaseXMLWrapper 
{ 
public: 
    void ListMembers (const char *parent) 
    { 
    // find "parent" in m_types 
    // if found, output members of vector 
    // else output "type not found" 
    } 
protected: 
    void RegisterInstance (const char *parent, const char *member) 
    { 
    // find 'parent' in m_types 
    // if not found, create a new vector and add it to m_types 
    // find 'member' in parent vector 
    // if not found, add it 
    } 
private: 
    static std::map <const std::string, std::vector <const std::string> > 
    m_types; 
}; 

class CXMLWrapper <class T, const char *parent> : BaseXMLWrapper 
{ 
public: 
    CXMLWrapper(const char* p_name) : m_local_name(p_name) 
    { 
    RegisterInstance (parent, p_name); 
    } 
    // you could override assignments, copy and move constructors to not call RegisterInstance 
    //skip the get_name() set_name()  
private: 
    m_local_name; 
} 

class object 
{ 
public: 
    object() : m_team("team"), m_base("base") 
    { 
    } 
public: 
    CXMLWrapper<string, "object"> m_team; 
    CXMLWrapper<string, "object"> m_base; 
    ... 
}; 

這不增加開銷的對象的建設,但由於它只是一個構造函數的開銷,可能不會影響整體系統性能很大。

+0

感謝您的回答,但我無法修改'CXMLWrapper'的佈局或層次結構。 'BaseXMLWrapper'是一個好主意! – jfly