如何重载 [][] 运算符?
一个类 A 有成员 double[][],我希望直接能在对象上进行类似这样的操作:
A a;
double x = a[0][0];该怎么实现?
需要一个 helper 类,大约是:
class ARowHelper {
friend class A;
A a_;
size_t r_;
ARowHelper(A a, size_t r) : a_(a), r_(r) {}
public:
double operator[](size_t c) { return a_.data_[r_][c]; }
};
class A {
double** data_;
public:
ARowHelper operator[](size_t r) { return ARowHelper(*this, r); }
};
实际上还要考虑 const-ness 等问题。
operator[]返回一个double*或者不就够了,使用时[][]里的第二个[]是指针自带。
不过存多维数组的话我还是推荐扁平化……
C++怎么实现效率尽可能高地带边界检查的多维数组模板类??www.zhihu.com与其重载[][]不如重载()。你所需要的操作它都能满足,而且也不失优雅。
[][]这种表达,很容易联想到一种数据类型,那就是矩阵:Matrix。
而关于Matrix该如何优雅的重载运算符。isocpp官方恰好有个demo,那就是重载 operator () 而不是[]:
class Matrix {
public:
Matrix(unsigned rows, unsigned cols);
double operator() (unsigned row, unsigned col); // Subscript operators often come in pairs
double operator() (unsigned row, unsigned col) const; // Subscript operators often come in pairs
// ...
~Matrix(); // Destructor
Matrix(const Matrix m); // Copy constructor
Matrix operator= (const Matrix m); // Assignment operator
// ...
private:
unsigned rows_, cols_;
double* data_;
};
inline
Matrix::Matrix(unsigned rows, unsigned cols)
: rows_ (rows)
, cols_ (cols)
//, data_ ← initialized below after the if...throw statement
{
if (rows == 0 || cols == 0)
throw BadIndex("Matrix constructor has 0 size");
data_ = new double[rows * cols];
}
inline
Matrix::~Matrix()
{
delete[] data_;
}
inline
double Matrix::operator() (unsigned row, unsigned col)
{
if (row &>= rows_ || col &>= cols_)
throw BadIndex("Matrix subscript out of bounds");
return data_[cols_*row + col];
}
inline
double Matrix::operator() (unsigned row, unsigned col) const
{
if (row &>= rows_ || col &>= cols_)
throw BadIndex("const Matrix subscript out of bounds");
return data_[cols_*row + col];
}
int main()
{
Matrix m(10,10);
m(5,8) = 106.15;
std::cout &
引用自:https://isocpp.org/wiki/faq/operator-overloading#matrix-subscript-op
[][] 的通过中间类还能实现。假如你日后需要[][][]呢?这并不稀奇,比如表示更高维的向量空间。
operator ()比之其他operator的一大好处就是不限制参数个数,并且()看著也并不突兀。
←_← 想好了,支持a[0][0]
就意味著(a[0])[0]
和[](auto r) { return r[0]; }(a[0])
都要有同样的语义。尤其是后一个,用户可能会拿r
做各种各样的操作,作为实现者要想好哪些操作有什么后果。
如果不想承受这种心智负担的话,还是不要支持这种写法为好。a.at(0, 0)
也没多长。
支持a[0][0]
的方式其他答主都解释过了,就是让operator[]
返回一个proxy。
模板大法好,可以套娃套一个任意维度的出来。上星期刚好写了一个。
用起来像这样: