67

私はしばらくの間 C# でプログラミングを行ってきましたが、今は C++ のスキルを磨きたいと思っています。

クラスを持つ:

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

最善のアプローチは何でしょうか(name_フィールドへの読み取りアクセスのみを許可したい):

  • getter メソッドを使用します。inline const std::string& name() const { return name_; }
  • 定数なので、フィールドをパブリックにします

ありがとう。

4

8 に答える 8

80

getter メソッドを使用することは、将来的に getter メソッドをより複雑なものに置き換えることができるため、有効期間の長いクラスではより適切な設計選択です。これが const 値に必要になる可能性は低いと思われますが、コストは低く、考えられる利点は大きくなります。

余談ですが、C++ では、メンバーの getter と setter の両方に同じ名前を付けることをお勧めします。これは、将来、メソッドのペアを実際に変更できるためです。

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

operator()()for eachを定義する単一のパブリック メンバー変数に:

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

もちろん、クライアント コードを再コンパイルする必要がありますが、構文を変更する必要はありません。明らかに、この変換は、getter のみが必要な const 値に対しても同様に機能します。

于 2009-04-17T15:26:34.213 に答える
24

余談ですが、C++ では、const 参照メンバーを持つことはやや奇妙です。コンストラクタリストで割り当てる必要があります。そのオブジェクトの実際のメモリを所有しているのは誰で、その寿命は何ですか?

スタイルに関しては、あなたがプライベートを公開したくないという他の人に同意します. :-) セッター/ゲッターのこのパターンが好きです

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

このようにして、次のようなことができます:

Foo f;
f.FirstName("Jim").LastName("Bob").Title("Programmer");
于 2009-04-18T03:07:25.573 に答える
8

C++11 のアプローチは、今ではもっと似ていると思います。

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

これを Visual Studio 2013 でテストしました。 残念ながら、LambdaSetter 内の基になるストレージを使用するには、カプセル化が壊れる可能性のある "GetRawData" パブリック アクセサーを提供する必要がありましたが、それを省略して独自のストレージ コンテナーを提供することもできます。 T または、"GetRawData" を使用するのは、カスタムの getter/setter メソッドを記述するときだけであることを確認してください。

于 2013-12-09T16:24:27.217 に答える
1

複数の C++ ソースからアイデアを集め、それを 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;
}

出力:

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

ここでオンラインでテストできます: http://codepad.org/zosxqjTX

PS: FO イヴェット <3

于 2018-10-25T21:04:20.510 に答える