I have this code of a class representing a matrix:
class Matrix {
private:
int** M;
int n, m;
public:
Matrix(int _n, int _m, int v) {
n = _n;
m = _m;
M = new int*[n];
for (int i = 0; i < n; i++)
M[i] = new int[m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++)
M[i][j] = v;
}
}
int operator() (unsigned row, unsigned col) {
return this -> M[row][col];
}
void set(int i, int j, int v) {
M[i][j] = v;
}
};
I can not change the content of a cell when I use this class in the main function or within another class. I can only access/diplay a cell thanks to operator(), but I can not change its value unless I use the method set().
I would like to know if there is a why? Maybe using other methods or operators, to access and modify the content of a cell outside the class Matrix?
Just like this:
Matrix m(4,4,0);
m(2,2) = 10000; // ERROR!
and not
m.set(2,2,10000);
You have made int **M a private variable. The idea of a private variable is that you explicitly cannot change it outside of the class (see http://www.cplusplus.com/doc/tutorial/classes/). You can do one of two things:
Return a reference to the element as:
int &operator() (unsigned row, unsigned col)
{
return M[row][col];
}
Make int **M a public variable. This will allow you to access m.M[2][2] in main.cpp as normal.
Related
I got a class Matrix and a class Row. Matrix has as member variable a pointer to a pointer of an object from class Row. I overloaded the operator [] for Matrix and Row. But somehow the overloaded operator from Row is never getting called and I can't figure out why not.
Example Code:
matrix.h
class Row
{
int* value;
int size;
public:
int& operator[](int i)
{
assert(i >= 0 && i < size);
return value[i];
}
};
class Matrix
{
private:
Row **mat; // Pointer to "Row"-Vector
int nrows, ncols; // Row- and Columnnumber
public:
Row& Matrix::operator[](int i){
assert(i >= 0 && i < nrows);
return *mat[i];
}
Row** getMat() {
return mat;
}
// Constructor
Matrix(int rows, int cols, int value);
};
matrix.cpp
#include "matrix.h"
Matrix::Matrix(int rows, int cols, int value) : nrows(rows), ncols(cols){
mat = new Row*[rows];
for(int i = 0; i < rows; i++) {
mat[i] = new Row(ncols);
for(int j = 0; j < ncols; j++){
// the operator-overload of Row[] isn't getting called and I don't get why not
mat[i][j] = value;
}
}
}
int main(){
Matrix m = new Matrix(2, 2, 4);
return 0;
mat[i] gives you Row*, and you want to call Row::operator[], but pointer to Row is not dereferenced automatically. So you have to dereference it manually: (*mat[i])[j].
So I just figured it out myself.
I tried to call the []-operator from Matrix through mat[][], but since mat is a Row** Row& Matrix::operator[](int i) is never getting called.
I created a matrix class by using a vector< vector >
structure. When created, the matrix is filled with zeroes (probably not the best way to do it, I'm planning to change it).
The header of the class goes something like this:
class Matrix{
public:
/*Basic constructor, accepts matrix dimensions
Matrix(int nr, int nc);
/*return element i,j*/
double elem(int i, int j);
/*operator () overloading - same thing as previous method*/
double operator()(int i, int j);
private:
vector<vector<double> > Matrix_;
int nr_, nc_;
};
while the implementation is:
//CONSTRUCTOR
Matrix::Matrix(int nrows, int ncols)
{
nc_ = ncols;
nr_ = nrows;
/*creates rows*/
for (int i = 0; i < nrows; i++)
{
vector<double> row;
Matrix_.push_back(row);
}
/*Fills matrix with zeroes*/
for (int i = 0; i < nr_; i++)
{
for (int j = 0; j < nc_; j++)
{
Matrix_[i].push_back(0);
}
}
}
/*method returning i,j element of the matrix (I overloaded () to do the same)*/
double Matrix::elem(int i, int j)
{
return Matrix_[i][j];
}
/*operator () overloading*/
double Matrix::operator()(int i, int j)
{
return Matrix_[i][j];
}
Finally, in the main program I have:
Matrix m1(rows, cols);
for (int i=0; i<rows; i++)
{
for (int j=0; j<cols; j++)
{
m1(i,j) = i*j;
/*OR, using the other method*/
m1.elem(i,j) = i*j;
}
}
and the problem is that I am always returned the error:
matrix.cpp:55:27: error: lvalue required as left operand of assignment
m1.elem(i,j) = i*j;
no matter if I am using the method .elem() or the operator ().
So, I guess the problem is that I am not accessing the elements the proper way to change their values, but I don't understand why.
Any suggestion would be greatly appreciated, thanks!
In order to be able to modify a matrix element you need to return a reference to it:
double& Matrix::elem(int i, int j) {
return Matrix_[i][j];
}
and:
double& Matrix::operator()(int i, int j) {
return Matrix_[i][j];
}
You can also add these for const matrices:
double Matrix::elem(int i, int j) const {
return Matrix_[i][j];
}
and:
double Matrix::operator()(int i, int j) const {
return Matrix_[i][j];
}
im working with simple 2D array,but in my copy constructor i encounter a problem.
Here's a excerpt from my code:
//default constructor
Matrix::Matrix(int r, int c)
{
rows = r;
cols = c;
mainArray = new int[rows*cols];
array = new int *[rows];
for (int i = 0; i < rows; i++)
array[i] = mainArray + (i*cols);
}
//at member
int& Matrix::at(int i, int j)
{
return array[i][j];
}
//copy constructor
Matrix::Matrix(const Matrix & obj)
{
rows = obj.rows;
cols = obj.cols;
mainArray = new int[rows*cols];
array = new int *[rows];
for (int i = 0; i < rows; i++)
array[i] = mainArray + (i*cols);
}
for (int i = 0; i < obj.rows; i++)
{
for (int j = 0; j < obj.cols; j++)
at(i, j) =obj.at(i,j);//PROBLEM
}
}
when im trying to assign at(i,j)=obj.at(i,j) i get this:
the object has type qualifiers that are not compatible with the member function
as far as i know, copy constructor is supposed to be passed by (const class& obj).
what should i do?
That's because your copy constructor take a const parameter, and your method Matrix::at is not const.
I suggest you to do two versions of your at method, one const and one not :
// Use for assignement
int& Matrix::at(int i, int j)
{
return array[i][j];
}
// Use for reading
int Matrix::at(int i, int j) const
{
return array[i][j];
}
Your compiler should know in which case call which one without your help, depending if you are trying to modify or just read your instance :
Matrix matrix(4, 4);
matrix.at(1, 2) = 42; // Assignement method called
int i = matrix.at(1, 2); // Read method called
Realize two versions of at function, one const and one non-const.
int& Matrix::at(int i, int j)
{
return array[i][j];
}
int Matrix::at(int i, int j) const
{
return array[i][j];
}
Assume I have a class A that has say 3 methods. So the first methods assigns some values to the first array and the rest of the methods in order modify what is computed by the previous method. Since I wanted to avoid designing the methods that return an array (pointer to local variable) I picked 3 data member and store the intermediate result in each of them. Please note that this simple code is used for illustration.
class A
{
public: // for now how the class members should be accessed isn't important
int * a, *b, *c;
A(int size)
{
a = new int [size];
b = new int [size];
c = new int [size];
}
void func_a()
{
int j = 1;
for int(i = 0; i < size; i++)
a[i] = j++; // assign different values
}
void func_b()
{
int k = 6;
for (int i = 0; i < size; i++)
b[i] = a[i] * (k++);
}
void func_c()
{
int p = 6;
for int (i = 0; i < size; i++)
c[i] = b[i] * (p++);
}
};
Clearly, if I have more methods I have to have more data members.
** I'd like to know how I can re-design the class (having methods that return some values and) at the same time, the class does not have the any of two issues (returning pointers and have many data member to store the intermediate values)
There are two possibilities. If you want each function to return a new array of values, you can write the following:
std::vector<int> func_a(std::vector<int> vec){
int j = 1;
for (auto& e : vec) {
e = j++;
}
return vec;
}
std::vector<int> func_b(std::vector<int> vec){
int j = 6;
for (auto& e : vec) {
e *= j++;
}
return vec;
}
std::vector<int> func_c(std::vector<int> vec){
//same as func_b
}
int main() {
std::vector<int> vec(10);
auto a=func_a(vec);
auto b=func_b(a);
auto c=func_c(b);
//or in one line
auto r = func_c(func_b(func_a(std::vector<int>(10))));
}
Or you can apply each function to the same vector:
void apply_func_a(std::vector<int>& vec){
int j = 1;
for (auto& e : vec) {
e = j++;
}
}
void apply_func_b(std::vector<int>& vec){
int j = 6;
for (auto& e : vec) {
e *= j++;
}
}
void apply_func_c(std::vector<int>& vec){
// same as apply_func_b
}
int main() {
std::vector<int> vec(10);
apply_func_a(vec);
apply_func_b(vec);
apply_func_c(vec);
}
I'm not a big fan of the third version (passing the input parameter as the output):
std::vector<int>& func_a(std::vector<int>& vec)
Most importantly, try to avoid C-style arrays and use std::vector or std::array, and don't use new, but std::make_unique and std::make_shared
I'm assuming you want to be able to modify a single array with no class-level attributes and without returning any pointers. Your above code can be modified to be a single function, but I've kept it as 3 to more closely match your code.
void func_a(int[] arr, int size){
for(int i = 0; i < size; i++)
arr[i] = i+1;
}
void func_b(int[] arr, int size){
int k = 6;
for(int i = 0; i < size; i++)
arr[i] *= (k+i);
}
//this function is exactly like func_b so it is really unnecessary
void func_c(int[] arr, int size){
int p = 6;
for(int i = 0; i < size; i++)
arr[i] *= (p+i);
}
But if you just want a single function:
void func(int[] arr, int size){
int j = 6;
for(int i = 0; i < size; i++)
arr[i] = (i+1) * (j+i) * (j+i);
}
This solution in other answers is better, if you are going to allocate memory then do it like this (and test it!) also if you are not using the default constructor and copy constructor then hide them, this will prevent calling them by accident
class A{
private:
A(const &A){}
A() {}//either define these or hide them as private
public:
int * a, *b, *c;
int size;
A(int sz) {
size = sz;
a = new int[size];
b = new int[size];
c = new int[size];
}
~A()
{
delete[]a;
delete[]b;
delete[]c;
}
//...
};
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Operator[][] overload
I have made class which contains an array containing (in one row) all the numbers from the given 2d array. For example given: {{1,2}{3,4}} the b field in the object of class T contains {1,2,3,4}. I would like to overload[][] operator for this class so it will work like that
T* t.....new etc.
int val = (*t)[i][j]; //I get t->b[i*j + j] b is an 1dimension array
class T{
public:
int* b;
int m, n;
T(int** a, int m, int n){
b = new int[m*n];
this->m = m;
this->n = n;
int counter = 0;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
b[counter] = a[i][j];
counter++;
}
}
}
int main()
{
int m = 3, n = 5, c = 0;
int** tab = new int*[m];
for(int i = 0; i < m; i++)
tab[i] = new int[n];
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
tab[i][j] = c;
c++;
cout<<tab[i][j]<<"\t";
}
cout<<"\n";
}
T* t = new T(tab,3,5);
};
You cannot. You have to overload operator[] to return a proxy object, that in turn, overloads operator[] to return the final value.
Something like:
class TRow
{
public:
TRow(T &t, int r)
:m_t(t), m_r(r)
{}
int operator[](int c)
{
return m_t.tab[m_t.n*m_r + c];
}
private:
T &m_t;
int m_r;
};
class T
{
friend class TRow;
/*...*/
public:
TRow operator[](int r)
{
return TRow(*this, r);
}
};
Instead of saving a T& in TRow you could save directly a pointer to the row, that's up to you.
A nice feature of this solution is that you can use the TRow for other things such as operator int*().
In the case of a 2d array, you don't need to create a proxy type. Just use int*:
#include <iostream>
class T {
public:
int m, n;
int *b;
T(int m, int n) : m(m), n(n), b(new int[m*n]) {
}
int*operator[](std::size_t i) {
return &b[i*m];
}
};
int main () {
T t(2,2);
t[0][0] = 1;
t[0][1] = 2;
t[1][0] = 3;
t[1][1] = 4;
std::cout << t.b[0] << t.b[1] << t.b[2] << t.b[3] << "\n";
}