使用下标和等于运算符重载进行赋值和检索
我花了很长时间试图解决这个问题。我想要做的是使用运算符重载,以便我的对象行为更像一个多维数组。我已经找到了几个小问题的解决方案,但每当我试图将所有问题放在一起时,都会出现这样或那样的问题,要么是左值赋值错误,要么是来自右值的无效初始化,或者只是直接的seg错误。如果您能给我提建议,我将不胜感激。
#include <iostream>
#include <vector>
#include <string>
class Matrix {
std::string **m;
public:
Matrix(int x, int y) {
m = new std::string*[x];
for (int i = 0; i < x; i++)
m[x] = new std::string[y];
}
class Proxy {
std::string *mm;
int lastIndex = 0;
public:
Proxy(std::string *s) : mm(s) {}
std::string &operator[](int index) {
lastIndex = index;
return mm[index];
}
std::string &operator=(std::string s) {
mm[lastIndex] = s;
return mm[lastIndex];
}
};
Proxy operator[](int index) {
return Proxy(m[index]);
}
};
int main()
{
Matrix *m = new Matrix(5, 5);
m[2][2] = std::string("It Works");
std::cout << m[2][2] << std::endl;
return 0;
解决方案
在main()
中,m
是指向Matrix
对象的指针,因此您需要取消引用该指针才能访问Matrix
对象,以便可以对其调用Matrix::operator[]
,例如:
int main()
{
Matrix *m = new Matrix(5, 5);
(*m)[2][2] = "It Works";
std::cout << (*m)[2][2] << std::endl;
delete m;
return 0;
}
Online Demo
否则,您的示例一开始并不真正需要指针,例如:
int main()
{
Matrix m(5, 5);
m[2][2] = "It Works";
std::cout << m[2][2] << std::endl;
return 0;
}
Online Demo
无论哪种方式,您的Proxy
根本不需要实现operator=
,例如:
class Proxy {
std::string *mm;
public:
Proxy(std::string *s) : mm(s) {}
std::string& operator[](int index) {
return mm[index];
}
};
m[2][2] = "...";
这样的语句不会调用您的Proxy::operator=
,它只会调用Proxy::operator[]
。需要像m[2] = "...";
这样的语句来调用Proxy::operator=
,这在多维方案中是没有意义的。
此外,您的Matrix
构造函数有错误-写入m[x]
超出m[]
数组的界限,因此数组实际上根本没有填充,并且您正在损坏周围的内存,和泄漏内存。您需要写信给m[i]
:
//m[x] = new std::string[y];
m[i] = new std::string[y];
修复后,Matrix
仍然,因为它没有实现析构函数来释放std::string
。您必须delete[]
new[]
(与delete
和new
相同)。
然后,您应该通过实现一个复制构造函数和一个复制赋值运算符(您的示例代码不需要它们,但生产代码应该始终具有它们)来完成对Rule of 3/5/0的支持,例如:
#include <iostream>
#include <string>
#include <utility>
class Matrix {
std::string **m;
int m_x, m_y;
public:
Matrix(int x = 0, int y = 0) : m_x(x), m_y(y) {
m = new std::string*[x];
for (int i = 0; i < x; ++i)
m[i] = new std::string[y];
}
Matrix(const Matrix &src) : m_x(src.m_x), m_y(src.m_y) {
m = new std::string*[m_x];
for (int i = 0; i < m_x; ++i) {
m[i] = new std::string[m_y];
for (int j = 0; j < m_y; ++j) {
m[i][j] = src.m[i][j];
}
}
}
~Matrix() {
for (int i = 0; i < m_x; ++i)
delete[] m[i];
delete[] m;
}
Matrix& operator=(const Matrix &rhs) {
if (&rhs != this) {
Matrix temp(rhs);
std::swap(m, temp.m);
std::swap(m_x, temp.m_x);
std::swap(m_y, temp.m_y);
}
return *this;
}
class Proxy {
std::string *mm;
public:
Proxy(std::string *s) : mm(s) {}
std::string& operator[](int index) {
return mm[index];
}
};
Proxy operator[](int index) {
return Proxy(m[index]);
}
};
int main()
{
Matrix m(5, 5);
m[2][2] = "It Works";
std::cout << m[2][2] << std::endl;
Matrix m2(m);
std::cout << m2[2][2] << std::endl;
Matrix m3;
m3 = m2;
std::cout << m3[2][2] << std::endl;
return 0;
}
Online Demo
但是,与其手动使用new[]
,不如考虑使用std::vector
(您已经知道了,因为您的代码中有#include <vector>
)。这样,3/5/0规则可以完全由编译器为您处理。std::vector
和std::string
都完全符合规则,因此Matrix
中的任何编译器生成的析构函数、复制构造函数和复制赋值操作符都将满足要求,例如:
#include <iostream>
#include <vector>
#include <string>
class Matrix {
std::vector<std::vector<std::string>> m;
public:
Matrix(int x = 0, int y = 0) {
m.resize(x);
for (int i = 0; i < x; ++i)
m[i].resize(y);
}
class Proxy {
std::vector<std::string> &mm;
public:
Proxy(std::vector<std::string> &s) : mm(s) {}
std::string& operator[](int index) {
return mm[index];
}
};
Proxy operator[](int index) {
return Proxy(m[index]);
}
};
Online Demo
相关文章