22

我无法区分操作员 [] 的 get 和 set 之间的区别。我需要说出这些函数调用之间的区别。

cout << data[5];
data[5] = 1;

我用谷歌搜索了它,我找到的答案仍然没有帮助。人们建议通过添加 const 来使方法的签名不同。我这样做了,他们仍然都调用了相同的方法。

有我用过的签名:

const T& operator[](unsigned int index) const;
T& operator[](unsigned int index);

我究竟做错了什么?

4

4 回答 4

26

解决方案是使用会延迟实际操作的“代理”对象:

#include <vector>
#include <iostream>

template<typename T>
struct MyArray {
    std::vector<T> data;
    MyArray(int size) : data(size) {}

    struct Deref {
        MyArray& a;
        int index;
        Deref(MyArray& a, int index) : a(a), index(index) {}

        operator T() {
            std::cout << "reading\n"; return a.data[index];
        }

        T& operator=(const T& other) {
            std::cout << "writing\n"; return a.data[index] = other;
        }
   };

   Deref operator[](int index) {
       return Deref(*this, index);
   }
};

int main(int argc, const char *argv[]) {
    MyArray<int> foo(3);
    foo[1] = 42;
    std::cout << "Value is " << foo[1] << "\n";
    return 0;
}

const不能使用简单-ness,因为您可能需要从非常量实例中读取,这就是您必须延迟操作的原因:赋值发生在访问“之后”并且编译器不会告诉您访问是否稍后将用作分配或不分配的目标。

因此,这个想法是,在访问时,您只需存储已请求的索引并等待知道是否正在发生读取或写入操作。通过向代理提供隐式转换运算符,T您知道何时发生读取操作,通过向代理提供赋值运算符,T您知道何时发生写入。

于 2013-10-07T05:53:47.607 回答
4

const版本意味着如果调用它的对象是,const则允许您调用该版本的[]运算符,并且只能调用该版本。

但如果对象不是,则可以调用const两个版本的运算符,但编译器将选择非常量版本。[]换句话说,对于非常量对象,非常量版本的运算符可以充当“setter”或“getter”。这就是为什么在您的示例中在两种情况下都调用相同版本的原因,因为您的data对象不是 const。

你必须做这样的事情:

const Data& data_cref = data;
cout << data_cref[5];  // calls the const version of operator[]

Data& data_ref = data;
data_ref[5] = 1;       // calls the non-const version of operator[]
于 2013-10-07T05:54:31.177 回答
1

为了与下标的普通含义兼容,下标运算符通常返回对被获取元素的引用。通过返回引用,可以在赋值的任一侧使用下标。

因此,定义此运算符的 const 和 nonconst 版本通常也是一个好主意。应用于对象时,下标应返回对 const 的引用,以便将其分配给返回的对象。

----C++入门,第五版

于 2013-10-07T05:57:53.090 回答
0

const您的版本operator[]将被称为const数据对象:

const Data data;
cout << data[5];
于 2013-10-07T05:48:54.883 回答