2009-05-04 8 views
3

Ich habe heute Morgen das Buch The Pragmatic Programmer Kapitel 3 über Basic Tools gelesen, die jeder Programmierer haben sollte und sie erwähnten Code Generation Tools. Sie erwähnten ein Perl-Skript für C++ - Programme, das dabei half, den Prozess der Implementierung der get/set() -Memberfunktionen für private Datenmitglieder zu automatisieren.Gibt es ein Perl-Skript zum Implementieren von C++ Class-Get/Set-Member-Funktionen?

Kennt jemand über ein solches Skript und wo es zu finden? Ich konnte die richtigen Google-Keywords nicht finden, um sie zu finden.

Antwort

9

Obwohl es Ihre Frage nicht direkt beantwortet, stellen Sie möglicherweise fest, dass generierter Code zum Verwalten von Eigenschaften in C++ tatsächlich nicht erforderlich ist. Der folgende Template-Code ermöglicht es Ihnen, und Eigenschaften bequem Gebrauch zu erklären:

// Declare your class containing a few properties 
class my_class { 
public: 
    property<int> x; 
    property<string> y; 
    ... 
}; 

... 

my_class obj; 
cout << obj.x();   // Get 
obj.y("Hello, world!"); // Set 

Hier ist der Code:

// Utility template to choose the 2nd type if the 1st is void 
template <typename T, typename U> 
struct replace_void { 
    typedef T type; 
}; 

template <typename T> 
struct replace_void<void, T> { 
    typedef T type; 
}; 

// Getter/setter template 
template <typename T, typename D = void> 
class property { 
    typedef typename replace_void<D, property>::type derived_type; 

    derived_type& derived() { return static_cast<derived_type&>(*this); } 

public: 
    property() {} // May be safer to omit the default ctor 
    explicit property(T const& v) : _v(v) {} 
    property(property const& p) : _v(p._v) {} 
    property& operator=(property const& p) { _v = p._v; return *this; } 

    T operator()() const { return _v; }     // Getter 
    void operator()(T const& v) { derived().check(v); _v = v; } // Setter 

protected: 
    // Default no-op check (derive to override) 
    void check(T const& v) const { (void)v; //avoid unused variable warning} 

private: 
    T _v; 
}; 

check() ist eine Funktion, der Wert überprüft, ob zugeordnet ist gültig ist. Sie können es in einer Unterklasse außer Kraft setzen:

class nonnegative_int : public property<int, nonnegative_int> { 
public: 
    // Have to redeclare all relevant ctors unfortunately :(
    nonnegative_int(int v) : property<int, nonnegative_int>(v) {} 

    void check(int const& v) const { 
     if (v < 0) { 
      throw "Yikes! A negative integer!"; 
     } 
    } 
}; 

Da haben Sie es - alle Vorteile von extern erzeugten Getter/Setter-Funktionen, mit keinem der mess! :)

Sie könnten wählen, check() eine bool zurückgeben, die Gültigkeit anzeigt, anstatt eine Ausnahme zu werfen. Und man könnte ein ähnliches Verfahren, access(), für den Fang von Lese Verweisen auf das Objekt im Prinzip hinzuzufügen.

EDIT: Wie Herr Fooz in den Kommentaren anmerkt, kann die Klasse Autor später die Implementierung ändern, ohne die logische Struktur der Klasse modifiziert (zB durch das property<int> x Mitglied mit einem Paar x() Methoden zu ersetzen), obwohl binären Die Kompatibilität ist verloren, daher müssen Benutzer ihren Client-Code immer dann neu kompilieren, wenn eine solche Änderung vorgenommen wird. Diese Fähigkeit, zukünftige Änderungen schmerzlos zu integrieren, ist eigentlich der Hauptgrund, warum Menschen Getter/Setter-Funktionen anstelle von öffentlichen Mitgliedern verwenden.

Leistung Anmerkung: Weil wir die CRTP verwenden „Kompilierung-Polymorphismus“ zu erreichen, gibt es keinen Overhead-virtual-Aufruf für die eigene check() in einer Unterklasse bereitstellt, und Sie müssen es nicht virtual zu erklären.

+0

Funktioniert das mit privaten Datenmitgliedern? – nmuntz

+1

Wow! Ich dachte eigentlich daran, Vorlagen zu verwenden, um Eigenschaften zu emulieren und kam zurück, um meine Antwort zu bearbeiten ... nur um diese Lösung bereits hier zu finden, und sie ist viel vollständiger als der einfache Hack, den ich posten würde! Danke für das Teilen. –

+1

Es ist wahrscheinlich erwähnenswert, dass der Klassenautor die Implementierung ändern kann, ohne die logische Struktur der Klasse zu ändern (zB indem man direkt ein Paar x() -Methoden erstellt oder die D-Implementierung ändert), aber die Binärkompatibilität ist verloren kompilieren Sie ihren Clientcode, sobald eine solche Änderung vorgenommen wird. –

3

Da die meisten privaten C++ - Member nicht über Get/Set-Style-Funktionen zugänglich sein sollten, scheint dies eine schlechte Idee zu sein.

Für ein einfaches Beispiel, warum dies so ist, betrachten Sie die C++ std :: string-Klasse. Seine privaten Mitglieder sehen wahrscheinlich so etwas wie diese (genaue Umsetzung nicht wichtig):

private: 
    int last, len; 
    char * data; 

Glauben Sie, es macht keinen Sinn get/set-Mitglieder für diejenigen zur Verfügung stellen?

+0

Wirklich? Dies ist das erste Mal, dass ich gelesen habe, dass get/set-Funktionen keine gute Idee sind. Würde es Ihnen etwas ausmachen, darüber nachzudenken, warum es eine schlechte Idee ist? Vielen Dank! – nmuntz

+3

Ich glaube nicht, dass Sie die Frage verstanden haben. Die Variablen sind privat, so dass die Klasse steuern kann, wie sie geändert werden, und die Möglichkeit hat, auf Änderungen zu reagieren, aber die öffentliche Schnittstelle zu diesen Variablen wird durch die get/set-Methoden implementiert. In einer Sprache wie C++, in der es keine Möglichkeit gibt, nachträglich Änderungen an einem Member zu ändern, ohne die öffentliche Schnittstelle zu ändern, ist dies keine schlechte Idee. –

+1

Ich verstehe was du meinst. Nicht alle privaten Datenmitglieder sollten Accessoren und/oder Mutatoren haben. Es ist jedoch einfach genug, nur die Methoden für die wenigen privaten Datenelemente zu löschen, auf die Sie in keiner Weise zugreifen möchten. Der Sinn eines Code-Generators ist es nicht, viel Zeit damit zu verschwenden, banalen, automatisierbaren Code zu schreiben. Im Idealfall ermöglicht Ihnen die Sprache die Angabe von Zugriffsrechten für ein Mitglied. Zum Beispiel, C# -Eigenschaften. C++ gibt Ihnen das nicht, daher werden Codegeneratoren verwendet, um diesen Mangel zu ergänzen. –

2

Ich kann Ihnen mit dem Standort dieses bestimmten Skripts nicht helfen. Es gibt jedoch quite a lot Code-Generierungstools. Vielleicht haben Sie sogar das, wonach Sie suchen, bereits Teil Ihrer IDE. Für weitere Debatte/Eingabe, wie, warum und ob Codegenerierungswerkzeuge verwenden, können Sie bei this stackoverflow question aussehen. Ich mag die akzeptierte Antwort auf diese Frage.

2

Ich kenne einen Programmierer, der uses Perl to augment the C preprocessor wenn es um Makros geht (latest version of that project). Die Grundidee ist, dass Sie auf einige Konvention entscheiden würde Ihr Perl-Skript zu sagen, wenn ein Getter oder Setter zu generieren:

struct My_struct { 
    //set 
    //get 
    int x; 

    int y; 

    //get 
    int z; 
}; 

wie dieser Gegeben Code, konnte ich ein Skript schreiben, für Kommentarzeilen des Kommentars aus zu sehen " Setzen Sie "oder" auf die Zeile (n) vor einer Membervariablendeklaration und ersetzen Sie sie dann durch einfache Setter/Getter. Im obigen Beispiel würde ich void set_x (int i), int get_x() und int get_z() nach die zugehörigen Member-Variablen-Definitionen generieren.

Ein Wort der Warnung: Tun Sie dies nicht in-Place mit s ///. Scannen Sie stattdessen jede Zeile einzeln, und wenn Sie eine geeignete Kommentarzeile finden, drücken Sie etwas mit der Aufschrift "Ich brauche einen Getter/Setter" auf einen Stapel. Wenn Sie dann die zugehörige Elementvariable sehen, können Sie den Stapel löschen und den Code generieren .

Es gibt ein paar Teufel in den Details, aber insgesamt ist das die Idee.

+1

+1. Da das Parsen ganz allgemeiner C++ - Deklarationen ziemlich schwierig ist, wette ich, dass Ihr Perl "Präprozessor" nur eine Teilmenge von relativ einfachen Deklarationen erkennt, was völlig in Ordnung ist - aber ich würde empfehlen, dass Ihr Skript aggressiv über jede Deklaration klagen könnte Entschlüssele nicht, um Probleme im Keim zu ersticken. Es ist immer besser, schnell zu versagen. –

+0

@j_random_hacker: Guter Punkt. –

2

Sie wollen ein Skript, um get/set Funktionen für Ihrer privaten Mitglieder unterschiedslos zu generieren? Das wäre kein sehr nützliches Skript; Sie werden es wahrscheinlich nicht in Google finden. Wenn Sie in der Lage sein möchten, Ihre Member-Variable irgendwie zu markieren und Getter- und/oder Setter-Skelette automatisch für Sie generieren zu lassen, dann erscheint ein IDE-Makro geeigneter. Probieren Sie Google dafür aus.

Verwandte Themen