我从std :: vector继承了我的类。现在我想重载[] -operator
当我尝试为我的矢量分配一个新值时,例如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
答案 0 :(得分:6)
导致此特定错误是因为您没有返回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
不是一个好主意,因此在尝试以多态方式销毁对象时可能会遇到麻烦。 / p>
您可能最好使用has-a
关系(您的类包含向量),而不是is-a
关系(您继承的地方)。
遗憾的是,您可能需要从类中创建大量的传递方法到底层向量(尽管只需要你需要的那些),但它将解决析构函数的问题。
(b)见(a): - )
答案 1 :(得分:4)
您需要返回对元素的引用 - 但请注意,即使您这样做,也会遇到无限递归 - 您的operator[]
会自行调用。
无论哪种方式 - 继承std::vector
都不是一个好主意。改为使用构图。
答案 2 :(得分: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” :你必须尽量使用{{1来删除动态分配的Vec或者做一个意外的按值切片复制 - 即使这样,如果你添加了数据成员,它可能只会咬你。您应该确保自己了解这些风险,然后进行自己的评估,但对于小型实用程序等,有时会从这些类继承高效 ....