質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

5567閲覧

行列クラスにおいて、行・列ごとの参照を返す関数を実装したい

dashi8

総合スコア11

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2017/10/16 14:28

###実現したいこと
c++の勉強のため、行列クラスを作っています。行列クラスのオブジェクトに行ごと(列ごと)にアクセスするため、大きさ1×n (m×1)の部分行列の参照を返すメンバ関数を作りたいです。しかし、実装方法が全く分かりません・・・。何かいい方法はあるでしょうか?ご教示お願いします。

###ソースコード
Matrix.h

c++

1#ifndef _Matrix_H_ 2#define _Matrix_H_ 3 4#include <bits/stdc++.h> 5using namespace std; 6 7class Matrix { 8public: 9 Matrix(int r, int c);//コンストラクタで行列の大きさを決定 10 Matrix(); 11 Matrix(const Matrix& A); 12 13 vector<vector<double> > ele; //行列の要素はvector配列で管理 14 15 void set(double first, ...); //要素をセット 16 void show(); //行列を標準出力に表示 17 int rownumber() const; //行数を返す 18 int columnumber() const; //列数を返す 19 20 21 //今回実装したい関数 22 Matrix& row(int n); //引数の行の参照を返す 23 Matrix& colum(int n); //引数の列の参照を返す 24 25 26 27  //演算子オーバーロード 28 //添え字演算子 29 vector<double>& operator[](int n); 30 31 //代入演算子 32 Matrix& operator=(const Matrix& A); 33 34 //二項演算子 35 Matrix operator+(const Matrix& A) const; 36 Matrix operator-(const Matrix& A) const; 37 Matrix operator*(const Matrix& A) const; 38 39 //単項演算子 40 Matrix operator+() const; 41 Matrix operator-() const; 42 Matrix& operator+=(const Matrix& A); 43 Matrix& operator-=(const Matrix& A); 44 Matrix& operator*=(const Matrix& A); 45 Matrix& operator*=(double k); 46 Matrix& operator/=(double k); 47 48 //比較演算子 49 bool operator==(const Matrix& A) const; 50 bool operator!=(const Matrix& A) const; 51 52 53private: 54 int _row; //行数 55 int _colum; //列数 56}; 57 58//二項演算子 59Matrix operator*(double k, const Matrix& A); 60Matrix operator*(const Matrix& A, double k); 61Matrix operator/(const Matrix& A, double k); 62 63 64 65#endif 66 67

Matrix.cpp

c++

1#include "Matrix.h" 2 3Matrix::Matrix(int r, int c){ 4 _row = r, _colum = c; 5 ele.resize(_row); 6 for(int i = 0; i < _row; i++) { 7 ele[i].resize(_colum); 8 } 9 for(int i = 0; i < _row; i++) { 10 for(int j = 0; j < _colum; j++) { 11 ele[i][j] = 0;//0で初期化 12 } 13 } 14} 15 16Matrix::Matrix(){ 17 _row = 1, _colum = 1; 18 ele.resize(1); 19 ele[0].resize(1); 20 ele[0][0] = 0; 21} 22 23Matrix::Matrix(const Matrix& A){ 24 _row = A.rownumber(), _colum = A.columnumber(); 25 ele.resize(_row); 26 for(int i = 0; i < _row; i++) { 27 ele[i].resize(_colum); 28 } 29 for(int i = 0; i < _row; i++) { 30 for(int j = 0; j < _colum; j++) { 31 ele[i][j] = A.ele[i][j]; 32 } 33 } 34} 35 36 37void Matrix::set(double first, ...){ 38 double element = first; 39 va_list args; 40 va_start(args, first); 41 for(int i = 0; i < _row; i++) { 42 for(int j = 0; j < _colum; j++) { 43 ele[i][j] = element; 44 element = va_arg(args, double); 45 } 46 } 47 va_end(args); 48} 49 50void Matrix::show(){ 51 for(int i = 0; i < _row; i++) { 52 for(int j = 0; j < _colum; j++) { 53 printf("%lf ", ele[i][j]); 54 } 55 printf("\n"); 56 } 57 printf("\n"); 58} 59 60int Matrix::rownumber() const { 61 return _row; 62} 63 64int Matrix::columnumber() const { 65 return _colum; 66} 67 68 69//今回実装したい関数 70Matrix& Matrix::row(int n){ 71 72//参照を返せるようにしたい 73 74} 75 76//今回実装したい関数 77Matrix& Matrix::colum(int n){ 78 79//参照を返せるようにしたい 80 81} 82 83 84//演算子オーバーロード 85vector<double>& Matrix::operator[](int n) { 86 return ele[n]; 87} 88 89Matrix& Matrix::operator=(const Matrix& A){ 90 this->_row = A.rownumber(); 91 this->_colum = A.columnumber(); 92 this->ele.resize(_row); 93 for(int i = 0; i < _row; i++) { 94 this->ele[i].resize(_colum); 95 } 96 97 for(int i = 0; i < _row; i++) { 98 for(int j = 0; j < _colum; j++) { 99 this->ele[i][j] = A.ele[i][j]; 100 } 101 } 102 return *this; 103} 104 105 106//以下省略

実現したい動作
main.cpp

c++

1#include <bits/stdc++.h> 2#include "Matrix.h" 3using namespace std; 4 5int main(){ 6 Matrix M(3, 3); 7 M.set(1.0, 2.0, 3.0, 8 4.0, 5.0, 6.0, 9 7.0, 8.0, 9.0); 10  M.show() 11 12 Matrix R(1, 3); 13 R.set(1.0, 1.0, 1.0); 14 M.row(0) = R; 15 M.show(); 16 //列の方も同様 17} 18 19/* 20標準出力に次のように出力 211.0 2.0 3.0 224.0 5.0 6.0 237.0 8.0 9.0 24 251.0 1.0 1.0 264.0 5.0 6.0 277.0 8.0 9.0 28 29*/ 30

###試したこと
Matrix&型ではなく、vector<double>&型を返す関数なら、行に関してのみ実装できました。列に関してはこっちもできていません。

c++

1vector<double>& Matrix::row(int n){ 2 return ele[n]; 3}

これは簡単ですね、、、。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

こんにちは。

事実上無理な気がします。

取り出したい「Matrixの参照」に対する「Matrixの実体」が必要です。しかし、取り出したいものは元のMatrixと形状が異なりますから、元のMatrixでは「実体」になりません。従って、row()やcol()のMatrixを取り出す度にその実体を生成する必要があり、それをいつ破棄するのか管理が難しすぎると思います。

素直にMatrixの実体を返却した方がまだ希望はあると思いますが、それでも難易度高そうです。
そのMatrix実体が元のMatrixが管理する配列へのポインタを保持し、かつ、外部に対して希望の形状のように見えるようI/Fする事になります。
その際「元のMatrixインスタンスから取り出したMatrixインスタンス」がアクセスする配列の所有権をどうするのか決めないとハマります。
元のMatrixインスタンスが管理する、もしくは、std::shared_ptrを使って共有管理するのどちらかだろうと思います。

M.row(0)が返却するものをSubMatrixのような別クラスのインスタンスにしておいた方が現実的なように感じます。それは元のMatrixへの参照と参照先の列番号や行番号を保持しておき、const Matrix&を受け取る代入演算子などを実装すれば、概ねやりたいことをできる筈です。
こちらならdoubleを返却するoperator[]を実装できるので自然ですし。

投稿2017/10/17 14:58

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dashi8

2017/10/18 15:25 編集

回答ありがとうございます。 >>いつ破棄するのか管理が難しすぎる 確かにその通りだと思いました。また、「元の配列が持つ配列へのポインタを保持するMatrixインスタンス」を作る方も難しいのですね。 別クラスのインスタンスを返却するというのは盲点でした。vector<vector<double>>*で元の配列へのポインタを保持するSubMatrixクラスをMatrixクラスに合成(MatrixがSubMatrixを包含)することで、下のような動作を実現することができました:main.cpp Matrix A(3, 3); Matrix B(3, 3); //それぞれ適当に要素をセット A.colum(0) = B.colum(0); これでやりたいことは概ねできました。ありがとうございます。 しかしSubMatrixクラスに関し、一つ分からないことがあります。 次のような動作を実装したいのですが:main.cpp Matrix A(1, 3); Matrix B(3, 3); //それぞれ適当に要素をセット M.row(0) = A; //この代入演算子を定義したい SubMatrixオブジェクトにMatrixオブジェクトを代入する演算は、二つのクラスの関係から定義できないように思います。上と同様の動作は M.row(0) = A.row(0); で実現できるのですが、演算子を定義しMatrixを直接代入することはできるのでしょうか。よろしければご教示ください。
Chironian

2017/10/18 16:35

SubMatrix& operator=(const Matrix& rhs);を定義すれば、できる筈と思います。1要素づつコピーすればできる筈ですよ。 もちろんrhsの構造がSubMatrixの構造と一致していることを確認し、異なっていたら例外を投げる等の対処も必要です。std::vectorをアクセスする際に、operator[]ではなく、at()を使えば範囲外ならエラーになるので簡単かも。
dashi8

2017/10/19 05:47

クラスの相互参照の方法を知らなかったためエラーが出ていたようです。MatrixとSubMatridで相互参照することで SubMatrix& operator=(const Matrix& rhs); を実装することができました。 >>at()を使えば範囲外ならエラーになるので簡単かも アドバイスありがとうございます。operator[]では境界チェックがめんどうだったのでat()を使おうと思います。 とても勉強になりました。ありがとうございました!
guest

0

std::valarray<double> を sliceする方が万倍楽ちゃいますか?

[追記]
columnを返すのやってみた:

C++

1#include <iostream> 2#include <algorithm> 3 4template<typename T> 5class column { 6public: 7 column(T* data, size_t cols) : data_(data), cols_(cols) {} 8 T& operator[](size_t row) { return data_[cols_*row]; } 9private: 10 T* data_; 11 size_t cols_; 12}; 13 14template<typename T> 15class matrix { 16public: 17 matrix(size_t rows, size_t cols) : cols_(cols), rows_(rows) { 18 data_ = new T[rows*cols]; 19 } 20 ~matrix() { delete[] data_; } 21 void fill(const T& val) { std::fill_n(data_, rows_*cols_, val); } 22 column<T> operator()(size_t col) { return column<T>(data_+col, cols_); } 23 T* operator[](size_t row) { return data_+cols_*row; } 24private: 25 T* data_; 26 size_t cols_; 27 size_t rows_; 28}; 29 30// おためし 31int main() { 32 using namespace std; 33 34 matrix<double> mtx(2,3); 35 mtx.fill(0.0); 36 column<double> clm = mtx(1); 37 clm[0] = 1.23; 38 clm[1] = 2.34; 39 40 for ( size_t r = 0; r < 2; ++r ) { 41 for ( size_t c = 0; c < 3; ++c ) { 42 cout << mtx[r][c] << ' '; 43 } 44 cout << endl; 45 } 46}

投稿2017/10/16 23:03

編集2017/10/19 00:54
episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dashi8

2017/10/17 14:15

回答ありがとうございます。std::valarrayクラスは初めて知りました。 確かに演算子オーバーロードの実装も含めとても楽で、sliceにより取り出したい行(列)の要素への参照を得ることはできました。しかし、これらを参照するMatrixオブジェクトを作ることができません・・・。良い方法はあるでしょうか?
episteme

2017/10/18 00:06

あー... ならば double mtx[R][C] を用意し、第n列なら &mtx[0][n] をひとつだけ返せばいいんじゃないかしら。そこからRずつ進めた先が mtx[1][n], mtx[2][n]... なんだから。 んで、Rずつ進めた先を勝手に参照してくれる class column を実装すれば: matrix m(R,C); column c = m.column(n); // n列を返す c[3] = 1.23; // みたいな。
dashi8

2017/10/18 15:40

確かに別のクラスcolumnを介せば所望する参照を得られますね。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問