2

C++での演算子のオーバーロードについて質問があります。

割り当てのために、JavaのArrayListのような配列を含むクラスを作成する必要があります。

私がしなければならないことの1つは、配列のサイズを追跡することです。サイズは含まれる要素の量ですが、容量はクラスが配列を拡張する前に含めることができる最大量です。

クライアントコードは、コンストラクターを呼び出すときにサイズを指定します。ただし、新しい要素が追加された場合、サイズを変更する方法を考え出す必要があります。

私の先生は、平等のさまざまな側面のために演算子をオーバーロードできることについて何かを言いました。これは本物ですか、それとも私は彼女を誤解しましたか?これがうまくいけば、それは私の問題に対する最適な解決策になるでしょう。

[]演算子の現在のオーバーロードは次のとおりです。

int & ArrayWrapper::operator [] (int position){

if(position == _size){
    if(_size == _capacity){
        changeCapacity(_capacity+10);
    }
}
return _array[position];
}

これは取得には問題なく機能しますが、誰かが「=」の左側から呼び出した場合に、サイズを拡張する必要があるかどうかを確認できるようにしたいと思います。

編集:これが本物ではない場合、誰かが問題の別の解決策を考えることができますか?私が考えた解決策の1つは、getSize()メソッドが呼び出されるたびに配列全体を通過するようにすることですが、安っぽいように見えるので、実際にはその解決策を使用したくありません。

編集:明確にするために、私は配列の拡張が機能するかどうかを尋ねていません。新しい要素が追加されるたびに、サイズに1を追加する必要があります。たとえば、クライアントがサイズ15と容量25の配列を作成し、Array [15]に何かを追加しようとすると、サイズを16に増やす必要があります。オーバーロードでそれを行う方法があるかどうか疑問に思いました。

4

3 に答える 3

2

単純なアプローチは、あなたが望むことを完全には実行しませんが、配列が可変であるconstか可変であるかをオーバーロードすることです。

これは、配列が割り当ての左側(左辺値として)で使用されているか、右側(右辺値として)で使用されているかを区別しません。変更が許可されているかどうかだけです。

// Mutable overload (returns a mutable reference)
int & operator[](size_t position) {
    if (position >= _size) {
        if (position >= _capatity) {
           // increase capacity
        }
        // increase size
    }
    return _array[position];
}

// Const overload (returns a value or const reference)
int operator[](size_t position) const {
    if (position >= _size) {
        throw std::out_of_range("Array position out of range");
    }
    return _array[position];
}

自分が割り当てられているかどうかを本当に知りたい場合は、参照用のプロキシを返す必要があります。これは、配列に書き込むための割り当てをオーバーロードし、要素の値を取得するための変換演算子を提供します。

class proxy {
public:
    proxy(ArrayWrapper & array, size_t position) :
        _array(array), _position(position) {}

    operator int() const {
        if (_position >= _array._array._size) {            
            throw std::out_of_range("Array position out of range");
        }
        return _array._array[_position];
    }

    proxy & operator=(int value) {
        if (_position >= _size) {
            if (_position >= _capatity) {
                // increase capacity
            }
            // increase size
        }
        _array._array[_position] = value;
        return *this;
    }

private:
    ArrayWrapper & _array;
    size_t _position;
};

friendおそらくこれを宣言する必要がありArrayWrapperます; 次に、これをから返しますoperator[]

proxy ArrayWrapper::operator[](size_t position) {
    return proxy(*this, position);
}
于 2012-09-04T15:41:07.723 に答える
1

このアプローチは問題ありません。ただし、コードにエラーがあります。配列の現在のサイズに100を加えたものに等しい位置で誰かがその演算子を呼び出すとどうなりますか?

于 2012-09-04T15:25:38.087 に答える
0

問題は、あなたがどちらの側にいるかによって、本当に異なる行動を望んでいるかどうかです=。基本的な考え方は問題なく機能しますが、どちらの側にいるかに関係なく配列を拡張します。例:

ArrayWrapper a(10);
std::cout << a[20] << std::end;

配列が拡張されます。ほとんどの場合、そのような場合、好ましい動作は上記のコードで例外を発生させることですが、

ArrayWrapper a(10);
a[20] = 3.14159;

働くために。これはプロキシを使用して可能です。最初に、とを定義double ArrayWrapper::get( int index ) constvoid ArrayWrapper::set( int index, double newValue )ます。インデックスが範囲外の場合、ゲッターは例外をスローしますが、セッターは配列を拡張します。次に、 operator[]次の行に沿ってプロキシを返します。

class ArrayWrapper::Proxy
{
    ArrayWrapper* myOwner;
    int           myIndex;
public:
    Proxy( ArrayWrapper& owner, int index )
        : myOwner( &owner )
        , myIndex( index )
    {
    }
    Proxy const& operator=( double newValue ) const
    {
        myOwner->set( myIndex, newValue );
    }
    operator double() const
    {
        return myOwner->get( myIndex );
    }
};

に慣れていない場合はoperator double()、オーバーロードされた変換演算子です。これが機能する方法は operator[]、が代入の左側にある場合、それは実際に代入されるプロキシになり、プロキシの代入演算子はset()関数に転送するというものです。それ以外の場合、プロキシは暗黙的にに変換されdouble、この変換は関数に転送され get()ます。

于 2012-09-04T15:44:08.623 に答える