-1

クラスを書いていますが、行列の追加に問題があります。演算子 + をオーバーロードする必要があることはわかっていますが、正確な方法はわかりません。何か案は ?

 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);
      }

演算子 '<<' ,'>>' をオーバーロードしましたが、演算子 + に問題があります。

残念ながら、私は評判が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...
4

3 に答える 3

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)
}

また、コピー コンストラクター、デストラクタ、および代入演算子 (おそらく移動コンストラクターと移動代入も) を追加するか、これらの操作を無効にすることを検討する必要があります。そうしないと、コンパイラが提供するデフォルトをコードで使用すると、重大な問題が発生します。

デストラクタを追加しないとメモリ リークが発生するため、必ずデストラクタを追加する必要があります。

于 2013-08-07T16:27:39.727 に答える
4

C++ で演算子をオーバーロードする最良の方法は、代入演算子 (およびそのコリージュ)に基づいて算術演算子 ( 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
}

この実装には 2 つの利点があります。

  • スケーラブル:の実装+は に基づいてい+=ます。そのため、オペレーターの動作は首尾一貫しており、操作可能です (重複したコードはありません)。
  • 効率的:代入演算子は二項演算子よりもキャッシュにやさしく (同じインスタンス、2 つを使用して結果を生成するインスタンスで操作します)、この実装では 1 つのコピーのみを使用します (の初期化で使用される明示的なコピーresult) 、このコードは、コンパイラがNRVOを実行できるように設計されているためです。

高度なトピック: 演算子のオーバーロードの自動化

Curiously Recurrent Template Patternを利用して、オペレーターのオーバーロードの実装を自動化できます。

CRTPとは何ですか?

CRTP は C++ のイディオムで、クラスはテンプレート クラスをテンプレート引数として継承します。例えば:

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比較演算子のセット全体は、そのうちの 1 つ ( is b < aa <= bis!(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 ライブラリには、このメソッドで実装された一連のヘルパーを含むヘッダーがあります: http://www.boost.org/doc/libs/1_54_0/libs/utility/operators.htm

于 2013-08-07T16:40:25.217 に答える