2017-02-18 4 views
6

私が知る限り、これは簡単な方法では不可能と思われます。メンバconstを作ることは、すべての人にとってconstになります。私は、読み取り専用のプロパティを持っているが、典型的な "ゲッタ"を避けたいと思います。私はconst public、mutable privateを好きです。これはC++でも可能ですか? 現在、私が考えることのできるのは、テンプレートとfriendのトリッキーです。私は今これを調べている。アクセサーラッパー関数を使用せずに、クラスの外部から変更できないパブリックメンバーを持つ方法はありますか?

私は愚かな質問のように見えるかもしれませんが、私はここまでの回答で驚いています。

+1

ほとんどすべては、いくつかの努力で可能であるが、それは努力の価値がありますか?なぜこれが欲しいのですか? – user463035818

+0

@tobiすべてが可能なわけではなく、関係する作業が何であるか分からない場合に、どのように努力するのか分かりますか?私はこれが欲しいです。なぜなら、ライブラリユーザーに、通常適用されるよりも少ない迂回で、使いやすいインターフェースを提供するのに便利だと思われるからです。 – rubenvb

+5

@rubenvb:関係する仕事にかかわらず、結果は残酷で、珍しく、そして最悪の場合、賢明になります。それはあなたのコードを維持しなければならないあなたの後継者に挑戦したいと思うものですか? –

答えて

3

可能な解決策は、外側の一方が下記のもののように、友人となっている内部クラスに基づくことができる。

struct S { 
    template<typename T> 
    class Prop { 
     friend struct S; 
     T t; 
     void operator=(T val) { t = val; } 
    public: 
     operator const T &() const { return t; } 
    }; 

    void f() { 
     prop = 42; 
    } 

    Prop<int> prop; 
}; 

int main() { 
    S s; 
    int i = s.prop; 
    //s.prop = 0; 
    s.f(); 
    return i, 0; 
} 

例に示されるように、クラスSは内部からプロパティを変更することができそのメンバ関数(S::fを参照)。一方、プロパティは他の方法で変更することはできませんが、実際の変数へのconst参照を返す指定された演算子を使用して読み込みます。

+0

私は一般的な考え方が気に入っていますが、これはいくつかの再利用可能なソース(読み込み専用と書き込み可能なプロパティの同じテンプレート)と関連するenable_ifハーブがありません。 – rubenvb

+0

@rubenvbカプセル化を中断したいが、その利点を取り戻したい。どういうわけか悪魔! :-) – skypjack

+2

したがって、約10行のコードを追加することで、値にアクセスするときに '()'を書く必要がなくなりました。これは改善ですか?私は 'namespace std;を使って' std :: '接頭辞の使い方を保存するというビジョンを得ました。つまり、20バイトを使用して5バイトを「保存」します。 –

3

他のもっと明白な解決策があるようです。パブリックconst参照メンバを使用して、プライベートな変更可能なメンバをポイントします。 live code here

#include <iostream> 

struct S { 
    private: 
    int member; 
    public: 
    const int& prop; 
    S() : member{42}, prop{member} {} 
    S(const S& s) : member{s.member}, prop{member} {} 
    S(S&& s) : member(s.member), prop{member} {} 
    S& operator=(const S& s) { member = s.member; return *this; } 
    S& operator=(S&& s) { member = s.member; return *this; } 
    void f() { member = 32; } 
}; 

int main() { 
    using namespace std; 

    S s; 
    int i = s.prop; 

    cout << i << endl; 
    cout << s.prop << endl; 

    S s2{s}; 

    // s.prop = 32; // ERROR: does not compile 
    s.f(); 

    cout << s.prop << endl; 
    cout << s2.prop << endl; 

    s2.f(); 
    S s3 = move(s2); 

    cout << s3.prop << endl; 

    S s4; 
    cout << s4.prop << endl; 
    s4 = s3; 
    cout << s4.prop << endl; 
    s4 = S{}; 
    cout << s4.prop << endl; 
} 
+0

これは、あなたのクラスを移動不可/割り当て解除可能にします。多分これらの演算子を再定義しますか? – Mehrdad

+0

@Mehrdadええ。編集しました... – Massa

+0

メモリ内に余分なスペースを消費します。 –

0

私はskypjackの答え@好きですが、このように何とかそれを書かれています:

#include <iostream> 

template <class Parent, class Value> class ROMember { 
    friend Parent; 
    Value v_; 
    inline ROMember(Value const &v) : v_{v} {} 
    inline ROMember(Value &&v) : v_{std::move(v)} {} 
    inline Value &operator=(Value const &v) { 
    v_ = v; 
    return v_; 
    } 
    inline Value &operator=(Value &&v) { 
    v_ = std::move(v); 
    return v_; 
    } 
    inline operator Value&() & { 
    return v_; 
    } 
    inline operator Value const &() const & { 
    return v_; 
    } 
    inline operator Value&&() && { 
    return std::move(v_); 
    } 

public: 
    inline Value const &operator()() const { return v_; } 
}; 

class S { 
    template <class T> using member_t = ROMember<S, T>; 

public: 
    member_t<int> val = 0; 
    void f() { val = 1; } 
}; 

int main() { 
    S s; 
    std::cout << s.val() << "\n"; 
    s.f(); 
    std::cout << s.val() << "\n"; 
    return 0; 
} 

一部enable_ifのは本当にコアへの一般的なように欠けているが、精神はそれを再作成することですコールをゲッターのように見えるようにします。

これは確かにトリッキーfriendです。

-1

あなたがそうのようなプロパティクラス内からスーパークラス不思議定期的なテンプレートパターンや友人を使用することができます。

#include <utility> 
#include <cassert> 

template<typename Super, typename T> 
class property { 
    friend Super; 

    protected: 
    T& operator=(const T& val) 
    { value = val; return value; } 

    T& operator=(T&& val)  
    { value = val; return value; } 

    operator T &&() && 
    { return std::move(value); } 

    public: 
    operator T const&() const& 
    { return value; } 

    private: 
    T value; 
}; 

struct wrap { 
    wrap() { 
    // Assign OK 
    prop1 = 5; // This is legal since we are friends 
    prop2 = 10; 
    prop3 = 15; 

    // Move OK 
    prop2 = std::move(prop1); 
    assert(prop1 == 5 && prop2 == 5); 

    // Swap OK 
    std::swap(prop2, prop3); 
    assert(prop2 == 15 && prop3 == 5); 
    } 
    property<wrap, int> prop1; 
    property<wrap, int> prop2; 
    property<wrap, int> prop3; 
}; 

int foo() { 
    wrap w{}; 
    w.prop1 = 5; // This is illegal since operator= is protected 
    return w.prop1; // But this is perfectly legal 
} 
+0

これは、既存の回答 – Caleth

関連する問題