2

私は異常な状況にあり、

次のようなクラスがあるとします。

template <typename T>
class C
{
    public :

    C (int size) : value_(size), some_other_member_(size) {}

    T &value () {return value_;}
    const T &value() const {return value_;}

    private :

    T value_;
    SomeOtherType some_other_member_;
 };

クライアントが member にフル アクセスできるように設計されたクラスは、が参照を返すvalue_ように、参照を返すことでクライアントにフル アクセスを与える必要があります。セッター/ゲッターのペアではうまくいきません。std::vectoroperator[]

ただし、 とは異なりstd::vector、クライアントがメンバーを完全に置換できるようにしたくありません。つまり、クライアントは のメンバーconstまたは非constメンバーを呼び出すことができるものとしますvalue_が、次のことは許可されません。

 C<SomeType> c(10);
 SomeType another_value(5);
 c.value() = another_value; // This shall not be allowed

クライアントに へのフル アクセスを許可する方法はありますかvalue_。ある意味では、クラスCはコンテナのようになりますが、含まれているものが初期化されると (コンストラクターを介して、 への要件がありますが、ここでは関係ありません)、クライアントは のメンバー関数を介してTのみ変更でき、置換はできません。割り当てによって。value_Tvalue_

ただし、Tコピー不可にする必要はありません。クラスCはコピーできるからです。問題の核心は、クラスCに見られるようにC、いくつかのメンバーがあり、それらはすべてsizeプロパティを持ち、構築されると、それらはすべて同じで構築され、代入によって置き換えることが許可されているsize場合、メンバーが同じプロパティvalue_を持たなくなる可能性があるという意味で、データ構造が破損しています。size

サイズTが同じ場合にのみコピーまたは割り当てを許可することもオプションではありません。オブジェクトをコピーすると、コピーC元とコピー先でサイズが異なる可能性があるためです。例えば、

C c1(10);
C c2(20);
c1 = c2;

完全に合理的です。のサイズc1が変更されますが、そのメンバーもすべて同じ新しいサイズに変更されるので、問題ありません。

問題を明確に述べたことを願っています。要約すると、基本的に必要なコンストラクターを持つ任意の型にすることができCますT。コピーして割り当てることができます。クライアントに実行してほしくない唯一のことは、throughへの代入です。TTvalue_C::value()

4

2 に答える 2

3

ユーザーがオブジェクトの非constメンバー関数を呼び出せるようにし、実際のオブジェクトへの参照を返したい場合、代入演算子は基本的にそれだけなので、代入を完全に禁止することはできません(書き換えることができます)a = bとしてa.operator=(b))。したがって、オブジェクトへのconst参照のみを返すか、含まれているオブジェクトを作成するnon_copyableか、割り当て可能なファクトを使用する必要があります。

個人的にはデザインを考え直すことをお勧めします。割り当てを禁止できたとしても、オブジェクトにメンバー関数がないという保証はありません。これは基本的に同じ考え方です(.swap(...)一般的な候補です)。したがって、呼び出しを許可している限り、実際には何も獲得していません。非constメンバー関数。

ただし、偶発的な割り当てを禁止することだけに関心がある場合は、そのような割り当てを行うのを難しくすることができます。が組み込みでない場合Tは、派生クラスを作成できます。このクラスは、パブリック代入演算子を公開せず、その参照を返します。

template <typename T>
class C{
public :
    class Derived: public T {
    private:
       Derived(int size):T(size) {}
       Derived& operator=(const Derived&) = default; //used C++11 syntax for brevity, for C++03 code it has to be implemented here
       Derived(const Derived&) = default; //don't want this class to be copyied outside of C
       ~Derived() = default;
       friend class C;    
    };

    C (int size) : value_(size), some_other_member_(size) {}
    Derived& value () {return value_;}
    const Derived& value() const {return value_;}
 private :
    Derived value_;
    SomeOtherType some_other_member_;
 };

これにより、継承によってすべてのパブリックメンバーにアクセスできるようになりますが、代入演算子(およびコンストラクター)は非表示になります。もちろん、c ++ 11を使用する場合、このコードは、moveコンストラクター/割り当てを使用/定義し、完全な転送を使用して、さまざまなコンストラクターを許可することで拡張できます。DerivedのT部分は、引き続きstatic_cast<T&>(C.value()) = foo;を使用して割り当てることができることに注意してください。

派生できないタイプ(組み込み...)をサポートするには、割り当てを除くすべての機能を公開するプロキシを作成する必要があります。

于 2012-12-09T13:36:44.233 に答える
1

あなたのゲッター/セッターの問題については、私は書きます

const T& value() const; // as getter
void value(const T&); // as setter

const T&(const-reference)を返すことは、次のような状況に完全に反しc.value() = 10ます(たとえば、ScottMeyersによる効果的なC++、項目23を参照)。

これでコピーの問題も解決すると思います。クラスはコピー可能のままです。

于 2012-12-09T13:34:17.903 に答える