#include <iostream>
#include <vector>
#include <assert.h>

#define M 2
#define N 2

template <class T>
class MatrixData {
public:
    MatrixData(int xx, int yy) : col(xx), row(yy), Value(xx * yy) {}
    MatrixData(int xx, int yy, const T& vv) : col(xx), row(yy), Value(xx * yy, vv) {}
  friend class Matrix1D;
  // proxy配列クラス
  class Matrix1D {
  public:
    Matrix1D(MatrixData<T>& arr, int xx) : array(arr), XIndex(xx) {}
    Matrix1D(const MatrixData<T>& arr, int xx) : array(arr), XIndex(xx) {}
    T& operator[](int YIndex) {
      return array.Value[array.row * XIndex + YIndex];
    }
  private:
    int XIndex;
    MatrixData<T>& array;
  };
  MatrixData<T> operator*(MatrixData<T>& md) {
    int i, j, k;
    MatrixData<T> tmp(col, md.row);
    T sum;

    // row == md.colの時しか乗算は定義出来ない

    assert(row == md.col);

    for (i = 0; i < row; i++)
      for (j = 0; j < col; j++) {
        sum = 0;
        for (k = 0; k < md.col; k++)
          sum += (*this)[i][k] * md[k][j];
        tmp[i][j] = sum;
      }

    return tmp;
  }
  Matrix1D operator[](int Xindex) {
    return Matrix1D(*this, Xindex);
  }
  //行列データを画面に表示する
  void ShowMatrix()
  {
   int i, j;

    for (i = 0; i < row; i++) {
      for (j = 0; j < col; j++)
        std::cout << (*this)[i][j] << ' ';
      std::cout << std::endl;
    }
  }
  //行列の第p行と第q行を入れ替える
  void ChangeMatrix(int p, int q)
  {
    int i;
    MatrixData<T> c = *this;

    for (i = 0; i < col; i++) {
      c[q][i] = (*this)[p][i];
      c[p][i] = (*this)[q][i];
    }

    Value = c.Value;
  }
private:
  std::vector<T> Value;
  int col;
  int row;
};

int main(void)
{
  MatrixData<double> a(M, N), b(M, N), c(M, N);

  a[0][0] = 1.0;
  a[0][1] = 2.0;
  a[1][0] = 3.0;
  a[1][1] = 4.0;
  b[0][0] = 5.0;
  b[0][1] = 6.0;
  b[1][0] = 7.0;
  b[1][1] = 8.0;

  std::cout << std::fixed;

  c = a * b;
  c.ShowMatrix();

  c.ChangeMatrix(0, 1);
  c.ShowMatrix();
}
