I need to implement matrix as a class in C++.
This is my class:
class {
private:
int rows, columns;
int **mat;
};
In the main, I need to start the matrix in the regular way. For example : m[0][0]=1;
I thought to overloading the operator[][] but it is forbidden.
I would like to get some help. thanks.
Instead, you could overload the function call operator (operator()()), to get something like this:
int operator()(int p_row, int p_column);
which is legal and clean. I would allow you to write something like this:
// Create and fill in matrix called 'm'...
int matrixElement = m(0, 0); // get element m[0][0]
// ...
Here is an example of how to overload this operator.
Let's say we have vector<vector<int>> xThe operator [][] is really (ignoring out of bounds) vector<int> b = x[0] then int = b[0] combined into one line. I.e accessing the first array then the subscript operator of the second.
Hope this helps.
You can store the data in a continuous array using std::vector and then supply your own indexing operator which returns a pointer to the beginning of the row.
class Matrix
{
int rows, columns;
std::vector<int> data;
public:
/*...*/
// The overloaded operator[] returns a pointer to the beginning
// of the requested row, which can then be indexed for the column
// without checking the boundaries.
int* operator[](int r){
return &data[r*columns];
}
};
Using a vector of vectors is less efficient because the data gets spread to different memory locations. If you need bounds checking you can wrap the pointer in your own class and overload its operator[].
Related
In my platformer game which I'm writing in Visual C++, each level will initially be stored as a 2-dimensional array of ints. I decided it would make more sense to store this array in a class, so I created a class called Level. It looks like this:
class Level {
private:
int map[20][30];
public:
Level(int a[20][30]) {
map = a;
}
int getcell(int row, int column) {
return map[row][column];
}
};
As far as I can see - from looking up tutorials on class constructors, and passing 2-dimensional arrays as parameters, this should work, so I really don't understand why it doesn't.
On the line where I do map = a, I get an error: Error: expression must be a modifiable lvalue. I've looked this error up on stackoverflow, but I can't find any answers which relate to my problem.
So, how can I fix this error?
This doesn't really have anything to do with a constructor. You cannot assign arrays in C++. Whether in the constructor, or anywhere else.
There are two ways to work around it. The first way is the brute force way. Instead of
map = a;
write a loop to copy the contents of the array from the constructor's parameter into the class member array.
The second way is to stuff the array into an intermediate class:
class Level {
public:
struct level_map {
int map[20][30];
};
private:
level_map map;
public:
Level(const level_map &initial_map) : map(initial_map)
{
}
int getcell(int row, int column) {
return level_map.map[row][column];
}
};
This may or may not be practical, and introduces a little bit more complexity.
But the real answer here is to use std::vectors instead of plain arrays, which will solve all of these problems.
Others have already mentioned the real reason: you cannot assign an array to another using = operator. My two cents about your class:
map is not a good name, it may get conflict with std::map if using namespace std; or using std::map was specified somewhere.
The constant array sizes make this class non-reusable. Class should be flexible to allow any N*M sized 2D array. For this, better to use vector<vector<int>>.
getcell should be a const method, and it should do error checking with row and column numbers passed.
If you want this class to have static-sized array sizes and compile time, you may use class templates with row and column sizes as non type template arguments.
template<size_t row, size_t column>
class Level
{
int _map[row][column];
public:
Level(int src[row][column])
{
memcpy(_map, src, sizeof(_map)); // why not simply 'memcpy' ?
}
};
int main()
{
int source[10][2] = { {1, 2}, {3,4} };
Level<10, 2> ten_by_2(source);
}
Here the map is a constant value, which could not been assigned as an lvalue. This could be fixed by iterating the element of the array, and assign a[i][j] to map[i][j].
class Level {
private:
int map[20][30];
public:
Level(int a[20][30]) {
for(int i = 0; i < 20; ++i)
for(int j = 0; j < 30; ++j)
map[i][j] = a[i][j];
}
int getcell(int row, int column) {
return map[row][column];
}
};
I have defined one matrix class, and overloaded the + operator to be able to add instances of this class together.
class Matrix{
public:
vector<vector<int>> a;
Matrix & operator+(const Matrix& b)
{
vector<vector<int>>::const_iterator it0=b.a.begin();
vector<vector<int>>::iterator it1=this->a.begin();
vector<int>::iterator it2=it1->begin();
vector<int>::iterator it3=it1->end();
vector<int>::const_iterator it01=it0->begin();
for(it1;it1!=this->a.end();it1++)
{
it2=it1->begin();
it3=it1->end();
it01=it0->begin();
it0++;
// a.begin(),a.end(),b.begin(),ret.begin()
std::transform(it2,it3,it01,it2,std::plus<int>());
}
return *this;
}
};
But then, there is also another way of doing this,
class Matrix{
public:
vector<vector<int> > a;
Matrix & operator + (const Matrix &y) {
for (int m=0; m<y.a.size(); ++m) {
for (int n=0; n<y.a[0].size(); ++n) {
this->a[m][n] = this->a[m][n] + y.a[m][n];
}
}
return *this;
}};
The second form is shorter, but uses arrays directly, while the first one uses iterators. Maybe it's possible to do this with iterators in a shorter way, I'm not sure. I've tested with simple cases and they seem to be equally efficient.
What's the proper way of doing this?
For non-trivial classes (such as classes including a std::vector), in-place operations are often cheaper than allocating a new object and then (presumably) destroying one or both of the arguments. However, aggressive use of rvalue reference overloads can somewhat mitigate this.
Note that regardless of which function implementation I used, I would not use nested std::vectors - I would either use a single std::vector or better a std::unique_ptr<T[]> and then calculate the index as y*w+x (remember to bounds-check first).
I got a little problem with templates and pointer. I'm trying to create a 2d array for some different matrices with different types. I have to do it with templates and references where it makes sense.
My main function looks like this, I'm not allowed to change it:
int main(){
int row, column;
cin >> row;
cin >> column;
int** M1;
double** M2;
reserve(M1, row, column);
reserve(M2, row, column);
return 0;
}
So my reserve function would look something like this:
template <typename S>
void reserve(S &x, int row, int column){
x = new S*[row];
for(int i = 0; i < row; ++i) {
x[i] = new S[column];
}
}
My problem is that I'm not getting the solution for this function. I tried it every way I could think about but nothing works.
I think the problem is that I'm not working correct with the type** pointer in combination with the type-parameter. In the version I posted above, im getting errors like:
error: cannot convert ‘int****’ to ‘int**’ in assignment x = new S*[row];
Would love if someone could help me fixing this function.
Changing the signature of reserve to this should fix the compile error
template <typename S>
void reserve(S **&x, int row, int column)
Alternatively, you can implement reserve so that it returns the newly allocated array
template <typename S>
S** reserve(int row, int column)
{
S** x = new S*[row];
for (int i = 0; i < row; ++i) {
x[i] = new S[column];
}
return x;
}
Remember to delete the array using delete [] when you are done using it:)
Maybe something like this might help you; try to encapsulate the whole concept into a class object like this:
template<typename T>
class Matrix {
public:
typedef std::vector<T> Row;
private:
std::vector<Row> Mat;
unsigned numberRows;
unsigned numberColumns;
public:
Matrix();
explicit Matrix( std::vector<Row>& vRows );
Matrix( unsigned numRows, unsigned numColumns );
Matrix( unsigned numRows, unsigned numColumns, T** data );
~Matrix();
private:
void reserve( unsigned int numRows, unsigned int numColumns );
};
Where this reserve() method is part of the class object where only this class has access to it. This would act as a helper function for your class in implementing its multiple constructors. If you want to use dynamic memory for the elements this can be expanded to this:
template<typename T>
class Matrix {
public:
typedef std::vector<std::shared_ptr<T>> Row;
private:
std::vector<Row> Mat;
// All Else Would Be The Same; Only The Internal Methods Would Slightly
// Vary Due To The Use Of Smart Pointer And Dynamic Memory.
};
Then in your main this will simplify code.
int main() {
// Using Default Constructor
Matrix<float> fMat1;
// Using std::vector<Row> To Construct A Matrix
Matrix<int>::Row row1;
Matrix<int>::Row row2;
Matrix<int>::Row row3;
std::vector<Matrix<int>::Row> vRows
Matrix<int> iMat2( vRows );
// A Construct That Knows The Size Of The Matrix;
// But Doesn't Have The Data
Matrix<double> dMat3( 4, 4 ); // This Will Create A Size Of 4x4 Of
// Doubles And Initialize Everything To 0
// Same As Above, But Passing In Raw Data By Double Pointer.
float** pData = nullptr;
// Populate Pointer's Elements
unsigned int row, col;
// Store Size Of Row & Col Based On Pointer's Elements
Matrix<float>( row, col, pData );
return 0;
}
And that is about it! The constructors shouldn't be that hard to implement. And if you are only working with stack objects the first definition of the class will work, but if you need dynamic memory of all objects the second one will suite your needs and the use of smart pointers makes the cleaning up of dynamic memory much cleaner, easier and safer. Less prone to memory leaks.
This would also allow you to create a matrix when you have the data available upon creation of the matrix; or to make an empty matrix container available to set aside memory for later on when you are ready to populate it. You would just have to add the necessary methods to set, get data elements, and any appropriate operator overloads for performing basic operations. Maybe some public methods to do common work on data or to test if data is in matrix, etc.
Because this Matrix class is template the way it is; it is not subject to just basic raw day types. This can store class objects, structure, function pointers, events, threads, files and even more!
I am trying to compile this code:
class OthelloState {
public: // constructor
Othello(int r, int c);
/* other stuff */
private: // private data
const int rows;
const int columns;
int board[rows][columns];
}
I keep ending up with:
OthelloState.h:109: error: invalid use of non-static data member 'OthelloState::rows'
OthelloState.h:115: error: from this location
OthelloState.h:115: error: array bound is not an integer constant
OthelloState.h:112: error: invalid use of non-static data member 'OthelloState::columns'
OthelloState.h:115: error: from this location
OthelloState.h:115: error: array bound is not an integer constant
I assume that this means I have to make rows and columns static. But if I make them static, I cannot initialize either with from a constructor, the way I have to for this project...
Is there some other way I can do this?
PS: I know that in real Othello, the board is a square 8 by 8 grid...But after considering how long it would take the computer to generate the next best move on a partial 8 by 8 grid, we are not going to play with "real" Othello board (i.e. no predefined board sizes).
In C++, variable length arrays are not allowed. board[][] needs to know both of its dimensions at compile time. You can use vector<vector<int> > board;, if you want to initialize row and col at runtime.
class OthelloState {
public:
OthelloState(int r, int c);
private: // private data
const int rows; // should be 'unsigned int'
const int columns;
vector<vector<int> > board;
};
Other solution:
Suppose you know rows and cols at compile time then you can use template. That is as good as initializing row and col in constructor.
template<unsigned int row, unsigned int col>
class OthelloState {
public:
...
private:
int board[row][col];
};
Usage:
OthelloState<8,8> obj;
OthelloState<10,10> obj;
if it's always 8x8, then constants are a minimal solution. here's one way to declare it:
class OthelloState {
// ...
private:
enum { rows = 8, columns = 8 };
int board[rows][columns];
};
But after considering how long it would take the computer to generate
the next best move on a partial 8 by 8 grid, we are not going to play
with "real" Othello board (i.e. no predefined board sizes).
I deduce from that sentence that you're working on a homework assignment. If that's the case, then it might not be possible/practical for you to use Boost.MultiArray (unless your instructor advised you that it's okay to use Boost).
That leaves vector< vector<int> > which are a PITA to initialize properly. Before you can even use vector< vector<int> >, you have to loop through each inner vector and resize it.
Boost.MultiArray is basically just an overglorified wrapper around a 1D array of data. I therefore propose a third alternative: Roll up your own 2D wrapper around a flat one-dimensional vector. You can overload operator() to mimic the [][] behavior of 2D arrays:
int operator()(size_t row, size_t col) {/*compute index into 1D array*/}
I posted an example of this kind of wrapper here.
You're trying to dynamically define the size of a compile-time, fixed size array at runtime. You will need to dynamically allocate the memory. You also need your constructor to have the same name as your class
class OthelloState {
public: // constructor
OthelloState(int r, int c)
{
board = new int[r];
for(int i = 0; i < r; i++)
{
board[i] = new int[c];
}
}
/* other stuff */
private: // private data
const int rows;
const int columns;
int **board;
};
Make sure you have matching deletes for all your news in a destructor if you use this method, though
I have a task to write a class matrix in C++ and there is a condition, to override the operator [] for matrix so if I have a matrix with name Matrix with this "Matrix[0][0]" I must take it's first element, on it's first line. I have represented the matrix with two dimensional dynamic array and templates (T **matrix). Could you help me, please?
PS: This method I'm using to create the two dimensional array:
template <class T>
T ** Matrix<T>::createMatrix(unsigned int rows, unsigned int cols)
{
T** matrix = new T*[rows];
for (unsigned int i = 0; i < rows; i++) {
matrix[i] = new T[cols];
}
return matrix;
}
i assume matrix is a member variable of type T** of Matrix.
template< class T >
T* operator []( Matrix<T>& m, unsigned int row )
{
// maybe remember rows and assert(row<rows);
return m.matrix[ row ];
}
Now you may write something like
Matrix<T> m(50,9999);
m[42][1337];
to access element 1337 in row 42.
You can do this with two classes. The matrix class overrides [] and returns a row object. The row object overrides [] and returns a scalar.
What you want to do is return a T* in operator[], as it can then have operator[] applied to it natively and get the result that you want. However, I want to point out that it's pretty bad practice to leave your pointers raw.
You can't do that natively in C++, but you could simply instanciate your matrix this way:
Matrix<Matrix<int>> m;
This way the first [ ] returns another matrix which will return the item you want. Of course a much better name for your class then would be Vector, and a wrapper class called Matrix that creates an internal Vector<Vector<T>>.
The method you are using to create the matrix doesn't have anything to do with a class, as your requirements state. You are creating a simple T**, it doesn't make a difference that you are doing it in a class method.
Creating a matrix of T that can be used as in matrix[i][j] means that the expression matrix[i] must return a type on which operator [] is also defined to return a T. Therefore, the usual way to do it is break it down in steps:
Matrix<T> operator[] (int) returns a MatrixRow<T>&
MatrixRow<T>& operator[] (int) returns a T&
There will also be const versions of these operators to be used when reading values from the matrix (non-const versions will be used when writing to the matrix).
So, at the minimum, you should create a class with this interface:
template <typename T>
class Matrix {
public:
Matrix(int rows, int cols);
const MatrixRow<T>& operator[] (int row) const;
MatrixRow<T>& operator[] (int row);
}
PS: This reads like a homework question, is it one?