Cascading Member Functions

Pages: 12
Question about Cascading member functions.

I need an output that takes a Matrix class and transposes it.

we will call this function transpose();

Since its cascading, I need to return (*this) correct?

but I can't figure out how to transpose the class sent to the function without making changes to it.

for instance
1
2
3
4
5
6
Matrix one(5,4); // creates a matrix 5 rows 4 columns
cout << "one\n" << one;
Matrix two = one.transpose(); // makes changes to one and the assignment operator takes the values
cout << "one\n" << one;
cout << "two\n" << two;
Matrix three = one.transpose().transpose(); // this returns the values assigned at matrix two because i made direct changes to *this,(double transpose = the same output) 


.cpp code:
1
2
3
4
5
6
7
8
9
Matrix & Matrix::transpose()
{
//copy matrix one
//delete old array
//create new array with new size
//copy data from the copy into matrix one
//delete copy
return *this
}


output:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
one
0 0 0 0 
0 0 0 0 
0 0 0 0
0 0 0 0
0 0 0 0 

one 
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0

two
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0


I need the object sent to transpose to remain the same but also make it cascading, how does one do that?




Last edited on
Hi

Your method must be some thing like following

1
2
3
4
5
6
7
8
9
10
11
Matrix Matrix::transpose()
{

   Matrix tmp(this->col, this->row);
   for(int i = 0 ; i < this->row ; i++)
       for(int j = 0 ; j < this->col ; j++)
         tmp[j][i] = this->[i][j];

   return tmp;

}


and you must implement copy-constructor Matrix(const Matrix& orig) and assigment operator operator= in your class
Last edited on
What's the return type of 'transpose'? Matrix or Matrix&? In the first case, the second ('cascaded') transpose won't actually work on 'one', but on a copy returned by the first transpose. Make sure you actually get the result you expected (even if it's not yet the one you wanted!).

In any case, if you want transpose not to affect the matrix it's called on, you should either make a temporary copy and return it by value (return type Matrix), or call it on two and three rather than on one and make the return by reference (return type Matrix&):
1
2
3
Matrix one(5,4), two(one), three(one);
two.transpose();
three.transpose().transpose();
can you cascade that kind of function though?
Well we need transpose to be cascading, I thought the only way to cascade a member function was to return itself to the output with *this

We can't change the structure of the main.cpp which is how they grade us. We have to impliment the .h and class .cpp file to make our output resemble his. where he uses two = one.transpose(), and one.transpose().transpose() where one doesn't get affected by his test.out file and mine does.

please clarify
Last edited on

In your header file the method should be some thing like

Matrix transpose();

please provide your source code of the method transpose, so we could explain it well.
.h
1
2
Matrix & transpose(); //get the transpose of the current matrix  



.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   Matrix & Matrix::transpose()
   {
          //copy data
          Matrix trans(*this);
          
          //delete old data
          for( int i = 0; i < row; i++){
               delete [] mydata[i];     
          }            
          delete [] mydata;
         
          //create new arrays
          this->set_cols(trans.num_rows());
          this->set_rows(trans.num_cols());
          
          mydata = new double *[ this->num_rows()];
            
            for( int i = 0; i < this->num_rows(); i++){
                 mydata[i] = new double[this->num_cols()];     
            }  
            //copy over data
            for(int i = 0; i < trans.num_cols(); i++)
                    for(int j = 0; j < trans.num_rows(); j++)
                        this->mydata[i][j] = trans.mydata[j][i];
     return *this;
   }


I can't do it with your method because your method doesn't allow for
1
2
3
4
matrix one(5,4);
matrix two(5,4);

matrix two = one.transpose().transpose();
Last edited on
Hi

whoever has implemented the transpose Method has done a sh....t. it is all none sense

could you please provide constructor , copy-constructor and assigment operator too ?
Cascading just means you can call a function (often the same one) on the result. How doesn't actually matter. Generally you do this by returning a reference to *this, so that the next function call is to the same object as the previous. If the function returns by value, the next function call is executed on the temporary return object instead.

Here's an example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <algorithm>
class Matrix {
public:
	int a, b, c, d;
	Matrix(int A, int B, int C, int D) : a(A), b(B), c(C), d(D) { }
	Matrix transpose() {
		std::swap(b, c);
		return *this;
	}
	void print() { 	printf("%d\t%d\n%d\t%d\n",a, b, c, d); 	}
};

int main() {
	Matrix one(1, 5, 9, 13);
	Matrix two = one.transpose();
	Matrix three = one.transpose().transpose();
	one.print();
	two.print();
	three.print();
	return 0;
}


1       5
9       13
1       9
5       13
1       9
5       13

As you can see, matrix one is only transposed twice: once in the second line of the main and once in the third line of the main. However, if I change the return type of transpose to Matrix&, this happens:
1       9
5       13
1       9
5       13
1       9
5       13

Matrix one is now transposed three times: once in the second line of the main and twice in the third line of the main. That is why references are so interesting: rather than returning a copy, it returns the object itself.

If you want "one" to stay the same, you have two options:
1) Have transpose make a copy of *this, transpose the copy and return it. This can be chained, because the intermediate copies are useless anyway. The final result is saved into Two by means of a copy.

2) Copy one to two and three and then call a transpose that changes and returns *this (by reference!).

Either method requires some copying. Because of the way it's set up, it's always going to be explicit copying. If you want implicit copying, move the transpose function outside of your class definition:

Matrix transpose(Matrix rhs) { ... return rhs; }
This way, the copying is done automatically (parameter passing by value = make a copy to work on). While this might no longer be called chaining, it's essentially the same, even if it looks a bit different:
Matrix three = transpose(transpose(one));

I created that transpose method lol thanks therockon7throw

...

I was reading some other posts here and thought i had to delete old memory etc..
Seems I missed some posts. The transpose function you provided is, like therockon7throw said, complete nonsense. (So is mine, by the way. I just quickly hardcoded a 2x2 matrix class with a transpose function. Anyone who makes a Matrix class like that for anything else than a quick example should probably be stabbed.)
Well, my matrices need to be dynamic and be of any size,

i still can't figure out this tranpose using a cascading function, i tried to replicate the above post but it doesn't seem to work
@oonej

You delete memory only and only when it is really needed, for example in implmentation of operator= , in destructor, ~classname, and in methods such as resize, to compute or send a transpose of a given matrix you dont need to copy the , this, first and than destroy the current object, this, and than reallocate it, this...., than copy the origine data as it's transpose , Oh God, not that way :-)

you create a tmp object having row size of this as it column-size and having column-size of this as it's row-size, copy the value and return the tmp object , it is all...
Last edited on
By the way, an easy (but depending on the use not very efficient) way to handle MxN (M!=N) matrices is to create a PxP where P = max(M, N) matrix and remember the actual number of rows and columns. This way, you can transpose a matrix in-place:
1
2
3
4
5
6
7
8
9
10
11
12
void transpose() {
  // Set P = max(M, N)
  int P = cols;
  if (rows > P) P = rows;
  // Loop over half-matrix triangle and swap items.
  for (int i = 0; i < P; ++i) {
    for (int j = 0; j < i; ++j) {
      std::swap(elements[i][j], elements[j][i]); // Needs #include <algorithm>
    }
  }
  std::swap(cols, rows); // Switch M and N values.
}


In short, Matrix T functions as a MxN matrix, but behind the scenes it is actually a PxP (P is still max(M, N)) matrix. The P-M 'last' rows and the P-N 'last' columns are simply ignored.
before i get caught up in doing this,

can a void tranpose() function be cascaded?

matrix x = y.tranpose().transpose();

?
@therockon7throw

According to your steps I created this method:
1
2
3
4
5
6
7
8
9
10
Matrix Matrix::transpose()
   {
      Matrix trans(this->num_cols(), this->num_rows());
      
      for(int i = 0; i < trans.num_cols(); i++)
              for(int j = 0; j < trans.num_rows(); j++)
                       trans.mydata[j][i] = this->mydata[i][j];
         
   return trans;
   }


but i'm getting this error when trying to do test1.transpose().transpose();:
57 main.cpp res1 ^ T ^ T = \n")) << Matrix::transpose()()'

it works fine for test.transpose(); but doesn't allow for transpose().transpose();

If copy-constructor, assigment operator are correctly implemented, you can call

obj.transpose().transpose().transpose().transpose().transpose().transpose();

Your operator= should be some thing like following

in header file
Matrix& operator=(const Matrix& orig);

and in source file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Matrix& Matrix::operator=(const Matrix& orig)
{
	if( this == &orig )
		return *this;
      // check the sizes
     
    if( num_cols()!= orig.num_cols() || num_rows() != orig.num_rows() ){
         // here you should clean, destroy mydata and reallocate it
         // and set size of this to the size of orig
    }

   // here copy the value of orig elements(mydata's) to elements of this

     // and return 
	return *this;
}


and your copy-constructor

in header file
Matrix(const Matrix& orig);

and in source file

1
2
3
4
5
6
7
8
Matrix::Matrix(const Matrix& orig)
{

  // set size of this to the size of orig
 // allocate mydata
 // here copy the value of orig elements(mydata's) to elements of this mydata

}


Last edited on
this ... is too high for me .. but thanks good stuff for thinking over it .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Matrix& Matrix::operator=(const Matrix &source)
    {
       //check to see if they are the same
       if( this == &source) return *this;
         
      //check the sizes
       if(this->num_rows() != source.num_rows() || this->num_cols()!= source.num_cols())
       {
       //cleaning memory (destroying mydata)
               for( int i = 0; i < row; i++)
               {
                    delete [] mydata[i];     
               }            
         delete [] this->mydata; 
         
         //resizing and recreating mydata
         int row = source.num_rows();
         int col = source.num_cols();
         this->set_rows(row);
         this->set_cols(col); 
         this->mydata = new double *[row];
            
            for( int i = 0; i < row; i++)
            {
                 this->mydata[i] = new double[col];     
            }       
       }
       
       //copying data over
       for(int i = 0; i < source.num_rows(); i++)
          for(int j = 0; j < source.num_cols(); j++)
             this->mydata[i][j] = source.mydata[i][j];     
    
       return *this;     
    }


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 Matrix::Matrix(const Matrix& other){
      set_rows(this->num_rows());
      set_cols(this->num_cols());
      
      mydata = new double *[this->num_rows()];
            
      for( int i = 0; i < row; i++){
           mydata[i] = new double[this->num_cols()];     
      }     
      //copy stuff
      for(int i = 0; i < this->num_rows(); i++){
           for(int j = 0; j < this->num_cols(); j++){
               this->mydata[i][j] = other.mydata[i][j];          
       }                            
     }
   }


1
2
3
4
5
6
7
8
9
10
   Matrix Matrix::transpose()
   {
      Matrix trans(this->num_cols(), this->num_rows());
      
      for(int i = 0; i < trans.num_cols(); i++)
              for(int j = 0; j < trans.num_rows(); j++)
                       trans.mydata[j][i] = this->mydata[i][j];
         
   return trans;
   }


still not working with .transpose().transpose() :(

res1.transpose().transpose();
change line 2 and 3 your copy-constructor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Matrix::Matrix(const Matrix& other){

      set_rows(other.num_rows());
      set_cols(other.num_cols());
      
      mydata = new double *[this->num_rows()];
            
      for( int i = 0; i < row; i++){
           mydata[i] = new double[this->num_cols()];     
      }     
      //copy stuff
      for(int i = 0; i < this->num_rows(); i++){
           for(int j = 0; j < this->num_cols(); j++){
               this->mydata[i][j] = other.mydata[i][j];          
       }                            
     }
   }
Pages: 12