2

我从 std::vector 继承了我的类。现在我想重载 [] 运算符。
当我尝试为我的向量分配一个新值时,例如v[0]=5,我应该收到消息OK

这是我的代码(我知道,这没有任何意义,我只是在玩弄):

#include<vector>
#include<iostream>
class Vec : public std::vector<int> {
public:
    int operator[](int);
};

int Vec::operator[](int i) {
    (*this)[i] = i;
    std::cout << "OK";
    return 123;
}

int main() {
    Vec v;
    v[0]=5;
}

不幸的是,我收到以下错误:

In member function ‘int Vec::operator[](int)’:
error: lvalue required as left operand of assignmen
In function ‘int main()’:
error: lvalue required as left operand of assignment
4

3 回答 3

7

特定错误是由于您没有返回 引起的lvalue,通常定义为可以出现在分配左侧的东西,例如v[0] = 5;. 正如其他答案中指出的那样,您还有更多问题,但这是您遇到该错误消息(a)的具体问题。

重载索引运算符的正确规范是:

int& operator[] (const int nIndex);

如果要将其视为lvalue. 以下代码显示了一个修复,尽管在这个简化的情况下,所有数组索引显然都映射到相同的值:

#include <vector>
#include <iostream>

class Vec : public std::vector<int> {
    public:
        int& operator[] (int);    // <-- note the '&'
    private:
        int xyzzy;
};

int& Vec::operator[] (int idx) {  // <-- note the '&'
    std::cout << "OK\n";
    return xyzzy;
}

int main () {
    Vec v;
    v[0] = 5;
    v[1] = 6;
    std::cout << v[22] << '\n';
    return 0;
}

这个的输出是:

OK
OK
OK
6

实际上,您不会将所有索引映射到相同的值,上面的代码只是为了说明正确的函数签名。我没有费心给出一个更完整的例子,因为使用非虚拟析构函数的子类经常会导致非平凡代码(b)中的问题。


(a)子类化通常不是一个好主意,std::vector因为析构函数不是虚拟的,因此在尝试以多态方式销毁对象时可能会遇到麻烦。

你可能最好使用has-a关系(你的类包含一个向量)而不是is-a关系(你继承的地方)。

不幸的是,这意味着您可能必须创建许多从类到底层向量的传递方法(尽管只有您需要的那些),但这将解决析构函数的问题。


(b)(a) :-)

于 2013-05-21T00:59:12.633 回答
5

您需要返回对您的元素的引用 - 但请注意,即使您这样做了,您也会遇到无限递归 - 您的operator[]调用本身。

无论哪种方式 - 继承std::vector都不是一个好主意。改用合成。

于 2013-05-21T00:50:25.907 回答
3

下面的代码说明了如何operator[]vector基类调用...。

#include <iostream>
#include <vector>

struct Vec : std::vector<int>
{
    int& operator[](int n)
    {
        std::cout << "operator[](" << n << ")\n";
        return std::vector<int>::operator[](n);
    }
};

int main()
{
    Vec v;
    v.push_back(10);
    v.push_back(20);
    v[0] += 5;
    std::cout << v[0] << ' ' << v[1] << '\n';
}

运行时输出:

operator[](0)
operator[](1)
operator[](0)
15 20

不要太认真地谈论“不要从 std::vector 继承” :您必须竭尽全力使用 a 删除动态分配的 Vec std::vector<int>*,或者进行意外的按值切片复制 - 甚至那么如果您添加了数据成员,它可能只会咬您。您应该确保您了解这些风险,然后进行自己的评估,但是对于小型实用程序等,有时从这些类继承是有成效的......

于 2013-05-21T01:14:50.257 回答