2

我有一个关于 C++ 中的运算符重载的问题。

对于作业,我必须编写一个包含数组的类,有点像 Java 中的 ArrayList。

我必须做的一件事是跟踪数组的大小。大小是包含的元素数量,而容量是在类必须扩展数组之前可以包含的最大数量。

客户端代码在调用构造函数时指定大小。但是,当添加新元素时,我必须想办法改变大小。

我的老师说了一些关于能够为等式的不同方面重载运算符的内容。这是真的吗,还是我误会了她?如果这行得通,那将是我的问题的最佳解决方案。

我当前对 [] 运算符的重载是:

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

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

这适用于检索,但我想拥有它,以便如果有人从“=”的左侧调用它,那么它会检查它是否需要扩展大小。

编辑:如果这不是真的,任何人都可以想出不同的解决方案来解决这个问题吗?我想到的一种解决方案是让 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;
};

您可能需要声明此 a friendof 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 ) constand void ArrayWrapper::set( int index, double newValue ); 如果索引超出范围,getter 将抛出异常,但 setter 将扩展数组。然后, 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 回答