3

テンプレート クラスの Subscript('[]') 演算子をオーバーロードする方法を探しているときに、2 つの異なる手法に出会いました。

最初のテクニック:

コンテナーへの戻りポインターを直接オーバーロードしoperator []ます。これにより、値の読み取りと値の割り当ての両方が可能になります。この手法の実装例:

template <class T>
class X
{
    int _size;
    T *container;
public:
    X(int sz)
    {
        _size=sz;
        container=new T[sz]();
    }
    ~X()
    {

    }

    T& operator [](int indx)
    {
        return container[indx];
    }

};

次のようにmain():

X<int> sample(100);
cout<<sample[9]<<endl;
sample[9]=9;
cout<<sample[9]<<endl;

出力:

0
9

2 番目のテクニック:

2 番目の手法では、プロキシ クラスを宣言し、operator =そのクラスを介してオーバーロードします。この手法の実装例:

template <class T>
class X
{
    int _size;
    T *container;
public:
    X(int sz)
    {
        _size=sz;
        container=new T[sz]();
    }
    ~X()
    {

    }

    class Proxy
    {
        int indx;
        X<T> &parent;
    public:
        Proxy(X<T> &p, int x) : parent(p),indx(x)
        {

        }
        void operator =(T assgn)
        {
            parent.container[indx]=assgn;
        }
        operator T const &()
        {
            return parent.container[indx];
        }
        friend class X<T>;//unnecessary line, I know!
    };
    Proxy operator[](int indx)
    {
        return Proxy(*this,indx);
    }

};

同じmain()で、同じ出力が得られます。

私は個人的に2番目の方法が好きです。しかし、私は本当にこれら2つの方法を比較したい. これら 2 つの手法の主な機能上の違いは何ですか。これらの方法にはそれぞれどのような利点がありますか?

4

3 に答える 3

4

説明したプロキシベースの手法は、そのまま保存されていない(ストレージとの間の変換が必要な)要素のシーケンスを公開する場合、または単に参照によってアクセスできない場合に使用できます。例は std::vector < bool > です。これは、ストレージ内のすべてのバイトに 8 つの bool (各ビットに 1 つ) をパックします。それらをそのように格納すると、そのような単一のブール値への参照を返すことができないため、インデックス演算子は代わりに「プロキシオブジェクト」を返し、含まれているブール値の読み取りと書き込みをサポートします。

格納されたオブジェクトへの直接参照を返すことができる場合、割り当てを制限したい場合 (たとえば、コンテナー内で正の値のみを許可する場合) を除き、それをプロキシでラップする利点はありません。

于 2014-04-10T06:35:54.110 に答える
2

通常、プロキシは、データの内部ストレージと一致しないものを返したい場合に使用されます。古典的な例は、要素が単一の配列に格納されている 2D 行列です。行または列を返す演算子を提供する場合は、プロキシが必要です。もう 1 つの例は悪名高いstd::vector<bool>です。この場合、データを のブロックとして保存する必要はありませんがbool、アクセスboolはユーザーに返さなければなりません。

プロキシを使用して、内部データ表現のセグメントのさまざまな「ビュー」を返すことができます。あなたの例では、それらを使用する理由はないようです。

于 2014-04-10T06:37:48.163 に答える
2

ほとんどのクライアントの使用法に適したプロキシ オブジェクトを取得することは、かなりトリッキーです。たとえば、誰かが次のように言ったらどうでしょう。

tcp_peer.send_from_iterator_range(&sample[2], &sample[7+1]);

sample::operator[]一時的なプロキシが返され、そのプロキシが を慎重に置き換えない場合operator&、コードはプロキシ自体のアドレスを要求します。

一部のクライアントの使用法は、データへの読み取りおよび/または書き込みをインターセプトするプロキシの機能を失うことなくサポートすることはできません。たとえば...

Container::element_type& ref = container[n];
ref = 20;

...クライアントコードは、コンテナのoperator[]意志が実際の要素への参照を生成すると想定しています。によって返されるすべてのプロキシは、 - そのような参照を引き渡し、それ自体をプレイから外す - をoperator[]提供するか、拒否する (たとえば、参照のみを返す、非参照をバインドできない一時的な by 値を返す) および強制する必要があります。クライアントコードを編集します。operator element_type&()constconst

したがって、プロキシは、必要な場合は 95% 有効ですが、不要な場合は避けるのが最善です。

于 2014-04-10T08:15:29.930 に答える