我写了一个类,我有一个添加矩阵的问题。我知道我必须重载operator +,但我不知道究竟是怎么回事。任何想法?
class CMatrix
{
private:
int Rows;
int Columns;
float* pData;
public:
CMatrix(void);
CMatrix(int rows, int columns);
void setElement(int row, int column, float element);
float getElement(int row, int column);
...};
istream& operator>>(istream& in, CMatrix& matrix)
{
in >> matrix.Rows;
in >> matrix.Columns;
for(int i = 0; i < matrix.Rows; i++)
for(int j = 0; j < matrix.Columns; j++)
in >> *(matrix.pData + i * matrix.Columns + j);
return in;
}
CMatrix::CMatrix(int rows, int columns)
{
Rows = rows;
Columns = columns;
pData = new float[Rows * Columns];
float* pEnd = &pData[Rows * Columns];
for(float* p = pData; p < pEnd; p++)
*p = 0.0;
}
void CMatrix::setElement(int row, int column, float element)
{
*(pData+ row * Columns + column) = element;
}
float CMatrix::getElement(int row, int column)
{
return *(pData + row * Columns + column);
}
我重载了运算符'&lt;&lt;' , '&GT;&GT;' ,但我对operator +有问题。
不幸的是,我的声誉不到10 ...所以如果我写的话:
CMatrix operator+(const CMatrix &lhs, const CMatrix &rhs)
{
Cmatrix result (Rows,Columns);
for(int i=0; i <Rows ; i++)
for( int j=0; j<Columns; j++)
result.setElement(i,j) = lhs.getElement(i,j) + rhs.getElement(i,j);
return result;
}
int main()
{
const int n = 10, m = 5;
CMatrix m1(n, m);
CMatrix m2(n, m);
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
m1.setElement(i, j, (float)(i * m + j));
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
m2.setElement(i, j, (float)(i * m + j));
cout<<m1+m2; // it doesn't work
Thanks all for help, i did it at last...
答案 0 :(得分:6)
除非您需要访问CMatrix
的私有成员来执行计算,否则我建议您使用以下原型创建非成员函数:
CMatrix operator+(const CMatrix &lhs, const CMatrix &rhs)
{
// Do the work
// You may need to throw exceptions based on incompatibilities between
// matrix configurations (i.e., dimensions)
}
您还应该添加复制构造函数,析构函数和赋值运算符(也可以是移动构造函数和移动赋值)或考虑禁用这些操作。如果不这样做,如果代码使用它们,您将遇到编译器提供的默认值的严重问题。
你绝对需要添加析构函数,因为如果不这样做,你会泄漏内存。
答案 1 :(得分:4)
在C ++中重载运算符的最佳方法是基于asigment运算符(operator+
及其集合)重载算术运算符(operator-
,operator+=
等)。
在你的情况下:
Matrix& operator+=(const Matrix& other)
{
/* Add operation stuff... */
return *this;
}
Matrix operator+(const Matrix& llhs , const Matrix& rhs)
{
Matrix result( lhs ); //Copy of the first operand.
result += rhs; //Add computation.
return result; //NRVO-friendly implementation
}
这种实现有两个好处:
+
的实施基于+=
。因此,运算符的行为是连贯的,可操作的(没有重复的代码)。result
的inicialization中使用的显式副本),因为此代码旨在让编译器执行NRVO。 您可以利用Curiously Recurrent Template Pattern自动执行运算符重载。
CRTP是一种C ++习语,其中一个类继承自模板类,并将其作为模板argumment。例如:
template<typename T>
struct Base { /* ... */ };
struct Derived : public Base<Derived> { /* ... */ };
CRTP的关键是基类可以访问(知道)从中派生的类。
在我们的例子中,我们可以使用对派生案例的这种访问来实现基类中的某个运算符,基于必须由派生类实现的运算符。
让我用一个例子解释一下:基于用户提供的等于运算符的实现,实现不等运算符。
template<typename T>
struct EqualityHelper
{
friend bool operator !=(const T& lhs , const T& rhs)
{
return !(lhs == rhs); //We use the operator== that T (The user class) implements.
}
};
我们可以使用该CRTP基础作为帮助程序类来实现从中继承的任何类的operator!=
。例如:
class Foo : public EqualityHelper<Foo> //Magic!
{
friend bool operator==(const Foo& lhs , const Foo& rhs)
{
/* Equality implementation */
}
};
int main()
{
Foo a,b;
if( a != b) //Muahahahaha
{
/* ... */
}
}
这可以扩展到任何运营商。看到这种方法的强大功能的最好例子是比较运算符。整套比较运算符可以在其中一个中实现(a > b
为b < a
,a <= b
为!(a > b)
等):
template<typename T>
struct ComparisonHelper //Comparison operators based in operator> provided by the user
{
friend bool operator<(const T& lhs , const T& rhs) { return rhs < lhs; }
friend bool operator<=(const T& lhs , const T& rhs) { return !(lhs > rhs); }
friend bool operator>=(const T& lhs , const T& rhs) { return !(lhs < rhs); }
};
最后,我们可以利用多重继承来同时使用多个帮助器:
//The complete set of logical comparison operators in six mantenible lines of code!
class Foo : public EqualityHelper<Foo> , public ComparisonHelper<Foo>
{
friend bool operator==(const Foo& lhs , const Foo& rhs)
{
/* Equality implementation */
}
friedn bool operator>(const Foo& lhs , const Foo& rhs)
{
/* Comparison implementation */
}
}
Boost libraries有一个标题,其中包含使用此方法实现的一组帮助:http://www.boost.org/doc/libs/1_54_0/libs/utility/operators.htm
答案 2 :(得分:0)
我只想评论Michael Goldshteyn的帖子,但我想我没有足够的声誉去做那个(笑)所以请考虑这个评论他的帖子:
如果您需要+运算符来访问CMatrix类的私有数据(在这种情况下需要这样做),您可以通过插入以下行来将此函数声明为您的CMatrix类中的朋友:
friend CMatrix operator+(const CMatrix &, const CMatrix &);
CMatrix类定义中的任何位置。这允许您在其他地方定义的重载操作符函数访问类的私有成员和受保护成员(如pData成员)。