C ++ - 基于赋值方重载[]运算符

时间:2011-09-14 02:13:25

标签: c++ operator-overloading

我正在尝试用c ++编写动态数组模板

我目前正在重载[]运算符,我想根据它们使用的赋值方面实现不同的行为。

#include <iostream>
...

template <class T>
T dynamic_array<T>::operator[](int idx) {
    return this->array[idx];
}

template <class T>
T& dynamic_array<T>::operator[](int idx) {
    return this->array[idx];
}

using namespace std;
int main() {
    dynamic_array<int>* temp = new dynamic_array<int>();

    // Uses the T& type since we are explicitly 
    // trying to modify the stored object
    (*temp)[0] = 1;

    // Uses the T type since nothing in the array 
    // should be modified outside the array
    int& b = (*temp)[0]; 

    // For instance...
    b = 4;
    cout<<(*temp)[0]; // Should still be 1
    return 0;
}

出于显而易见的原因,在尝试像这样重载时出现编译器错误。

有没有正确的方法呢?

到目前为止我的搜索还没有成功。我在重载[]运算符中看到的任何东西似乎都接受用户可以修改对象外部存储的项目。

我已经实现了使用的方法(instance(int i),update(int i,T obj))但是能够像常规数组一样使用这个类会很好。

2 个答案:

答案 0 :(得分:13)

您不能仅在返回类型上重载。

提供常量和非常量访问器重载的标准方法是区分this的常量:

T       & get()       { return x; }
const T & get() const { return x; }  // or T get() const;

对于常量版本,您可以返回const-reference或value,具体取决于T是什么 - const-reference可能更普遍有用。

(当然,代替get()你会写operator[](std::size_t i)。我只想保持简短。)


我认为这不会达到您想要的100%,但那是因为您的推理错误:int b = foo() 永远不会成为对任何内容的引用,甚至if foo()返回(const或非const)引用,因为b被声明为int类型,而不是int&。实际上,当你说int b = (*temp)[0];时,实际上你会调用非const版本但实际上并不是问题。 (要获得常量版本,您必须说int b = static_cast<const dynamic_array<int> &>(*temp)[0];(*static_cast<const dynamic_array<int> *>(temp))[0] - 但为什么要这么麻烦。)

答案 1 :(得分:8)

Scott Meyers在其中一本 Effective C ++ 书中谈到了这一点。基本上诀窍是从索引运算符(operator[]()operator[]() const)返回临时的const或非const代理对象,然后重载该代理类的赋值和隐式转换运算符。像这样:

template <class T>
class Array
{
  public:
    struct proxy {
      T& element;

      proxy(T& el) : element(el) {}

      operator const T& () const {
        return element; // For use on RHS of assignment
      }

      proxy& operator=(const T& rhs) {
        // For use on LHS of assignment
        // Add your logic here
      }
    };

    const proxy operator[](int i) const {
      return proxy(a[i]);
    }

    proxy operator[](int i) {
      return proxy(a[i]);
    }

  private:
     T* a;
};

我可能有一些细节错误,但我们的想法是推迟决定元素所在的分配的哪一方,直到实际尝试分配给它。也就是说,您不知道在operator []调用时将执行的操作,但是当您尝试分配给后续元素引用时,您肯定会这样做。