2013-08-06 3 views
7

Ich habe ein Objekt, jede Mitgliedsvariable in diesem Objekt hat einen Namen, den ich es durch den Aufruf von get_name() erwerben kann, was ich tun möchte, ist die Verkettung aller Namen der Mitgliedsvariablen in alphabetischer Reihenfolge, dann etwas tun. zum Beispiel:eine Funktion anstelle von Kopieren und Einfügen Programmierung

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

Ich muss hart Code wie folgt:

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

brauche ich eine Funktion, dies zu tun, anstatt das Kopieren und Einfügen, wenn das Objekt variiert. Jeder hat eine Idee?

+0

Haben Sie verschiedene Objekte mit verschiedenen Elementvariablen? – doctorlove

+2

Vielleicht können Sie eine Sammlung dafür verwenden? Vielleicht Vektor. Beispiel: Klassenobjekt {/*....*/ vector > einige_vars /*....*/} /*....*/ für (auto & it: o.some_vars {sign + = it. get_name;}) Oder vielleicht Dictionary/map –

+1

Es ist weniger eine Funktion und mehr * Reflektion *. Es gibt Möglichkeiten, ein gewisses Maß an Reflexion in C++ zu bieten, aber wenn Sie ohne es tun können, wäre es am besten. –

Antwort

2

Eine Möglichkeit, dies in normalem C++ zu tun, wenn alle Mitglieder derselben Klasse angehören oder von einer Basisklasse abgeleitet sind, besteht darin, eine variable Anzahl von Argumenten für eine Funktion zu verwenden. Ein Beispiel folgt.

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

Wenn die Typen aller Mitglieder unterschiedlich sind, können Sie variadische Vorlagen von C++ 11x suchen in: http://en.wikipedia.org/wiki/Variadic_Templates, aber ich kann nicht scheinen, einen Weg zu finden, es anders zu machen.

+0

Obwohl es keine perfekte Lösung ist, kann es jedoch viel doppelten Code entfernen. Ich kann einen Vektor verwenden, um die Zeichenfolgen in der FOR-Schleife zu halten, und sie in alphabetischer Reihenfolge sortieren, dann verketten. Vielen Dank! – jfly

-2

Das sieht wie ein „beobachten Muster“, man muss nur als Member-Variable eine einzelne Kopie im Objekt halten „string name_;“, und übergeben Sie die Referenz des name_s in CXMLWrapper wie folgt aus:

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

Ihr Code ist ** sehr ** gefährlich und nicht verwendbar in einem Kontext, in dem es normal sein sollte. Sie arbeiten mit Referenzen, so dass 'CXMLWrapper' und' obejct' nicht zugewiesen werden können. –

+1

Ich sehe kein Beobachtermuster darin – doctorlove

+0

@JanHerrmann Ich sehe keine Gefahr, und ich bin nicht klar, was Sie mit "kann nicht zugewiesen werden" bedeuten - Sie sprechen über Regel von drei/fünf/Null ? – doctorlove

0

Wenn Variablen, die einen Namen haben, denselben Typ haben (oder diese Typen einer Hierarchie angehören), können Sie die Karte dieser Variablen verwenden. Ist das nicht eine gute Art und Weise, aber vielleicht hilft es Ihnen

Beispiel

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 Sorry für meine Schreibfehler. Englisch in nicht meiner Muttersprache.

+1

Die Verwendung dieses Codes erzwingt eine stringgeformte Codierung. Wahrscheinlich möchten Sie die Member-Variablen auch als tatsächliche Member-Variablen, nicht nur in einer Karte nach Namen für die normale Verwendung versteckt – doctorlove

+0

@Dark_Daver danke für den Vorschlag, aber ich kann das Layout des Objekts nicht ändern, weil es ein Argument an mich übergeben wird. – jfly

0

Eine Methode ist eine externe Bibliothek mit Mitgliedsnamen zu haben, die die CXMLWrapper Klasse-Updates: -

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

Dieser Overhead für den Bau von Objekten hinzufügt, aber da es Overhead nur ein Konstruktor ist es vielleicht nicht beeinflussen Gesamtsystemleistung viel.

+0

Danke für die Antwort, aber ich kann das Layout oder die Hierarchie von 'CXMLWrapper' einfach nicht ändern. Der 'BaseXMLWrapper' ist eine gute Idee! – jfly

Verwandte Themen