Frage

Ich habe eine Zeit lang in C # worden Programmierung und jetzt möchte ich auf meine C ++ Kenntnisse auffrischen.

Mit der Klasse:

class Foo
{
    const std::string& name_;
    ...
};

Was wäre der beste Ansatz (Ich will nur Lesezugriff auf das name_ Feld ermöglichen):

  • verwenden, um eine Getter-Methode: inline const std::string& name() const { return name_; }
  • das Feld öffentlich machen, da es eine Konstante
  • ist

Danke.

War es hilfreich?

Lösung

Es neigt dazu, eine schlechte Idee zu sein, nicht konstante öffentliche Felder zu machen, weil es dann schwierig wird, die Fehlerprüfung Einschränkungen zu erzwingen und / oder Nebenwirkungen von Wertänderungen in der Zukunft hinzuzufügen.

In Ihrem Fall haben Sie eine const Feld, so dass die oben genannten Probleme sind kein Problem. Der größte Nachteil es ein öffentliches Gebiet der Herstellung ist, dass Sie Sperren die zugrunde liegende Implementierung nach unten. Zum Beispiel, wenn Sie in Zukunft die interne Darstellung zu einem C-String oder eine Unicode-Zeichenfolge, oder etwas anderes ändern wollte, dann würde brechen Sie alle Client-Code. Mit einem Getter, könnte man auf die Legacy-Darstellung konvertiert für Kunden bestehenden, während der neuere Funktionalität, um neue Benutzer über ein neu Getter bereitgestellt wird.

Ich würde noch vorschlagen, eine Getter-Methode wie die, die Sie oben gesetzt haben. Dies wird Ihre zukünftige Flexibilität maximieren.

Andere Tipps

Mit einer Getter-Methode wird eine besseres Design Wahl für eine langlebige Klasse ermöglicht es Ihnen, die Getter-Methode mit etwas komplizierter in der Zukunft zu ersetzen. Obwohl dies weniger wahrscheinlich scheint für einen const Wert benötigt werden, sind die Kosten niedrig und die möglichen Vorteile sind groß.

Als Nebenwirkung in C ++, dann ist es eine besonders gute Idee, sowohl die Getter und Setter für ein Mitglied geben den gleichen Namen , da in Zukunft können Sie dann tatsächlich die das Paar von Methoden ändern :

class Foo {
public:
    std::string const& name() const;          // Getter
    void name(std::string const& newName);    // Setter
    ...
};

In einem einzigen, öffentlichen Membervariable, die eine operator()() für jede definiert:

// This class encapsulates a fancier type of name
class fancy_name {
public:
    // Getter
    std::string const& operator()() const {
        return _compute_fancy_name();    // Does some internal work
    }

    // Setter
    void operator()(std::string const& newName) {
        _set_fancy_name(newName);        // Does some internal work
    }
    ...
};

class Foo {
public:
    fancy_name name;
    ...
};

Der Client-Code muss natürlich neu kompiliert werden, aber keine Syntax-Änderungen erforderlich sind! Offensichtlich ist diese Transformation funktioniert genauso gut für const Werte, bei denen nur ein Getter erforderlich ist.

Als Nebenwirkung in C ++, es ist etwas ungerade ein const Referenzelement zu haben. Sie haben es in der Konstruktor Liste zuzuordnen. Wem gehört die eigentlich Erinnerung an dem Objekt und was es ist Leben?

Wie für Stil, ich stimme mit den anderen, die Sie nicht wollen, Ihre Soldaten belichten. :-) Ich mag dieses Muster für Setter / Getter

class Foo
{
public:
  const string& FirstName() const;
  Foo& FirstName(const string& newFirstName);

  const string& LastName() const;
  Foo& LastName(const string& newLastName);

  const string& Title() const;
  Foo& Title(const string& newTitle);
};

So können Sie etwas tun können, wie:

Foo f;
f.FirstName("Jim").LastName("Bob").Title("Programmer");

ich denke, die C ++ 11 Ansatz jetzt eher wie dieses wäre.

#include <string>
#include <iostream>
#include <functional>

template<typename T>
class LambdaSetter {
public:
    LambdaSetter() :
        getter([&]() -> T { return m_value; }),
        setter([&](T value) { m_value = value; }),
        m_value()
    {}

    T operator()() { return getter(); }
    void operator()(T value) { setter(value); }

    LambdaSetter operator=(T rhs)
    {
        setter(rhs);
        return *this;
    }

    T operator=(LambdaSetter rhs)
    {
        return rhs.getter();
    }

    operator T()
    { 
        return getter();
    }


    void SetGetter(std::function<T()> func) { getter = func; }
    void SetSetter(std::function<void(T)> func) { setter = func; }

    T& GetRawData() { return m_value; }

private:
    T m_value;
    std::function<const T()> getter;
    std::function<void(T)> setter;

    template <typename TT>
    friend std::ostream & operator<<(std::ostream &os, const LambdaSetter<TT>& p);

    template <typename TT>
    friend std::istream & operator>>(std::istream &is, const LambdaSetter<TT>& p);
};

template <typename T>
std::ostream & operator<<(std::ostream &os, const LambdaSetter<T>& p)
{
    os << p.getter();
    return os;
}

template <typename TT>
std::istream & operator>>(std::istream &is, const LambdaSetter<TT>& p)
{
    TT value;
    is >> value;
    p.setter(value);
    return is;
}


class foo {
public:
    foo()
    {
        myString.SetGetter([&]() -> std::string { 
            myString.GetRawData() = "Hello";
            return myString.GetRawData();
        });
        myString2.SetSetter([&](std::string value) -> void { 
            myString2.GetRawData() = (value + "!"); 
        });
    }


    LambdaSetter<std::string> myString;
    LambdaSetter<std::string> myString2;
};

int _tmain(int argc, _TCHAR* argv[])
{
    foo f;
    std::string hi = f.myString;

    f.myString2 = "world";

    std::cout << hi << " " << f.myString2 << std::endl;

    std::cin >> f.myString2;

    std::cout << hi << " " << f.myString2 << std::endl;

    return 0;
}

Getestet habe ich diese in Visual Studio 2013. Leider, um die zugrunde liegenden Speicher innerhalb des LambdaSetter verwende ich eine „GetRawData“ öffentlichen Accessor benötigt, um die zu defektem Verkapselung führen kann, aber man kann es entweder verlassen und Ihre eigene liefern Vorratsbehälter für T oder nur sicherstellen, dass die einzige Zeit, die Sie „GetRawData“ verwenden, wenn Sie eine benutzerdefinierte Getter / Setter-Methode zu schreiben.

Auch wenn der Name unveränderlich ist, können Sie immer noch die Möglichkeit haben, es von Rechen anstatt sie in einem Feld zu speichern. (Ich weiß, dies ist unwahrscheinlich, dass für „namen“, aber lassen Sie sich für den allgemeinen Fall zielen.) Aus diesem Grunde sogar konstante Felder werden am besten innerhalb von Getter eingewickelt:

class Foo {
    public:
        const std::string& getName() const {return name_;}
    private:
        const std::string& name_;
};

Beachten Sie, wenn Sie sind getName() zu ändern, um einen berechneten Wert zurückzukehren, ist es nicht const ref zurückkehren kann. Das ist in Ordnung, weil es keine Änderungen an den Anrufer erfordern (Modulo Neuübersetzung.)

Vermeiden Sie öffentliche Variablen, außer Klassen für die im Wesentlichen C-Stil structs sind. Es ist einfach keine gute Praxis in zu erhalten.

Wenn Sie die Klasse Schnittstelle definiert haben, können Sie nie in der Lage sein, es zu ändern (außer ihm hinzufügen), weil die Menschen auf sie bauen und vertrauen darauf. eine Variable öffentlich zu machen bedeutet, dass Sie die Variable haben müssen, und Sie müssen sicherstellen, dass es hat, was der Benutzer braucht.

Nun, wenn Sie einen Getter verwenden, sind viel versprechende Sie einige Informationen zu liefern, die derzeit in diesen Variablen gehalten wird. Wenn sich die Situation ändert, und Sie lieber nicht, dass variable ganze Zeit halten, können Sie den Zugriff ändern. Wenn du die Anforderungen ändern (und ich habe ein paar ziemlich seltsame Anforderungen Änderungen zu sehen ist), und Sie meistens müssen die Namen, das in diesen Variablen ist aber manchmal die man in diesen Variablen können Sie nur den Getter ändern. Wenn Sie die Variable öffentlich gemacht, dann würden Sie mit ihm stecken werden.

Dies wird nicht immer passieren, aber ich finde es viel einfacher, nur einen schnellen Getter zu schreiben, als die Situation zu analysieren, um zu sehen, ob ich die Variable öffentlich zu machen bereuen würde (und das Risiko falsch später ist).

Herstellung Membervariablen privat ist eine gute Gewohnheit, in zu erhalten. Jeder Laden, die Code-Standards hat wahrscheinlich geht die gelegentliche Membervariable Öffentlichkeit verbieten machen, und jedes Geschäft mit Code-Reviews ist wahrscheinlich, dass Sie es kritisieren.

Immer dann, wenn es wirklich nicht für eine einfache Schreib Materie, erhalten in den sichereren Gewohnheit.

Gesammelte Ideen aus mehreren C ++ Quellen und steckt es in ein schönes, noch recht einfaches Beispiel für Getter / Setter in C ++:

class Canvas { public:
    void resize() {
        cout << "resize to " << width << " " << height << endl;
    }

    Canvas(int w, int h) : width(*this), height(*this) {
        cout << "new canvas " << w << " " << h << endl;
        width.value = w;
        height.value = h;
    }

    class Width { public:
        Canvas& canvas;
        int value;
        Width(Canvas& canvas): canvas(canvas) {}
        int & operator = (const int &i) {
            value = i;
            canvas.resize();
            return value;
        }
        operator int () const {
            return value;
        }
    } width;

    class Height { public:
        Canvas& canvas;
        int value;
        Height(Canvas& canvas): canvas(canvas) {}
        int & operator = (const int &i) {
            value = i;
            canvas.resize();
            return value;
        }
        operator int () const {
            return value;
        }
    } height;
};

int main() {
    Canvas canvas(256, 256);
    canvas.width = 128;
    canvas.height = 64;
}

Ausgabe:

new canvas 256 256
resize to 128 256
resize to 128 64

Sie können es online testen hier: http://codepad.org/zosxqjTX

PS: FO Yvette <3

Von der Design Patterns Theorie; „Einkapseln, was variiert“. ein ‚Getter‘ gibt es gute Haftung auf das obige Prinzip Durch die Definition. Also, wenn die Umsetzung Darstellung der Mitglied Veränderungen in Zukunft kann das Element ‚massiert‘ werden, bevor aus dem ‚Getter‘ Rückkehr; keinen Code impliziert Refactoring auf der Client-Seite, wo der ‚Getter‘ Anruf getätigt wird.

Grüße,

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top