You are not logged in.

Dear visitor, welcome to QtForum.org. If this is your first visit here, please read the Help. It explains in detail how this page works. To use all features of this page, you should consider registering. Please use the registration form, to register here or read more information about the registration process. If you are already registered, please login here.

1

Monday, June 6th 2005, 3:31pm

Inheriting a template class

I'm trying to create a 2D Matrix by inheriting from std::vector. I know about Boost, but I'm just playing around with C++ to see if I can create one that is simple and easy to use, just like std:: vector.

Here's how I'm trying to create my Matrix class. I do this by :

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//matrix.h
#include <vector>

template <class T>
class CMatrix2D : public std::vector< std::vector<T> >
{
public:
	CMatrix2D(){}
	CMatrix2D(int rows, int cols) : std::vector< std::vector<T> >(){
		resize(rows, cols);
	}
	CMatrix2D(int rows, int cols, T val) {
		resize(rows, cols, val);
	}
	
	void resize(int rows, int cols, T val = NULL);
	
};


The code for resize is given as follows:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
//matrix.cpp
#include "matrix.h"

template <typename T>
void CMatrix2D<T>::resize(int rows, int cols, T val) 
{
	for(int j = 0; j < rows; j++) 
	{
		std::vector<T> temp;
		temp.resize(cols, val);
		push_back(temp);
	}
}


I'm testing the code with the following file

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//main.cpp
#include <iostream>
#include "matrix.h"

using namespace std;

int main (int argc, char * const argv[]) {
	CMatrix2D<double> m(3,3,4);
		
	for(int j = 0; j < m.size(); j++) {
		for(int i=0; i < m[j].size(); i++)
			cout<<m[j][i]<<"\t";
		cout<<endl;
	}
	
    std::cout << "Hello, World!\n";
    return 0;
}


Here's where I run into problems. The code compiles alright, but when I run it, it bombs when I enter the constructor. I'm guessing that the reason for this is because I am calling resize in the constructor, before the object has been fully created. If this is the reason, how do I go about resizing the object in the constructor?

All these years of Java have really ruined me :D. Thanks for taking the time.

Edit: corrected the [code] tag

This post has been edited 1 times, last edit by "wysota" (Jun 6th 2005, 3:56pm)


Jesse

Intermediate

  • "Jesse" is male

Posts: 194

Occupation: Systems Engineer

  • Send private message

2

Monday, June 6th 2005, 5:13pm

why do you call the resize and push_back? Either declare the size outside of the for loop, or call push_back only. push_back automatically allocates memory if it has to.

3

Monday, June 6th 2005, 5:28pm

Basically, what I've done is encapsulated a vector in a vector. Thus my 2D matrix is made up of a vector< vector <T> >. In my code, push_back is called on the outer vector, while resize is called on the inner vector, if that makes sense.

Here is how I could change it to totally use resize, but it still crashes.

Source code

1
2
3
4
5
6
7
#include "matrix.h"

template <typename T>
void CMatrix2D<T>::resize(int rows, int cols, T val) 
{	
	resize(rows, vector<T>(cols, val));
}

This post has been edited 1 times, last edit by "Viro" (Jun 6th 2005, 5:31pm)


4

Monday, June 6th 2005, 5:35pm

The original code works now. I just moved everything into the header file (from matrix.cpp) and it works fine now(!!?).

Jesse

Intermediate

  • "Jesse" is male

Posts: 194

Occupation: Systems Engineer

  • Send private message

5

Monday, June 6th 2005, 6:52pm

templates are always declared and defined in headers. Just how they are coded.

I would have just used

Source code

1
2
3
4
5
6
7
8
9
void CMatrix2D<T>::resize(int rows, int cols, T val) 
{
	for(int j = 0; j < rows; j++) 
	{
		std::vector<T> temp;
		//temp.resize(cols, val);
		push_back(temp);
	}
}

This post has been edited 1 times, last edit by "Jesse" (Jun 6th 2005, 6:53pm)


6

Monday, June 6th 2005, 10:30pm

Quoted

Originally posted by Viro
Basically, what I've done is encapsulated a vector in a vector. Thus my 2D matrix is made up of a vector< vector <T> >. In my code, push_back is called on the outer vector, while resize is called on the inner vector, if that makes sense.

Here is how I could change it to totally use resize, but it still crashes.

Source code

1
2
3
4
5
6
7
#include "matrix.h"

template <typename T>
void CMatrix2D<T>::resize(int rows, int cols, T val) 
{	
	resize(rows, vector<T>(cols, val));
}


Anyone able to shed any light on why this doesn't work? I thought it should, since I'm calling vector::resize but it seems to bomb and says that it can't find the definition of resize. I've moved it from the .cpp file to the header and it doesn't seem to make any difference at all.

jacek

Master

  • "jacek" is male

Posts: 2,729

Location: Warsaw, Poland

  • Send private message

7

Monday, June 6th 2005, 10:49pm

RE: Inheriting a template class

Quoted

Originally posted by Viro
I'm trying to create a 2D Matrix by inheriting from std::vector.
...

Source code

1
2
3
4
5
6
7
8
9
//matrix.h
#include <vector>

template <class T>
class CMatrix2D : public std::vector< std::vector<T> >
{
public:
...
};

Your CMatrix2D class will behave also like a vector. I think you should use agregation instead of inheritance. Like this:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <class T>
class CMatrix2D
{
   typedef std::vector<std::vector<T>> Matrix;
   
   public:
      ...
      T& operator( unsigned int r, unsigned int c );
      const T& operator( unsigned int r, unsigned int c ) const;
      ...

   private:
      Matrix _matrix;
};

8

Tuesday, June 7th 2005, 8:31am

Aggregation would be the one way of doing it, but I am trying to do it via inheritance. The reasons for my choice are both from a philosophical/design and a practical point of view.

A vector is a 1xm 1D matrix. As such a 2D matrix can be seen as composition of multiple 1D matrices, i.e. many vectors. A 2D matrix is still a vector, albeit a specific form of vector. That means that all the operations that apply to a vector, should apply to a 2D matrix too. Hence, I'm implementing it via inheritance.

Another reason for inheritance is to save on writing code. Now my matrix class has only the constructor that was written by me, and the resize method. Everything else is inherited from vector, and so far it all works as expected.

jacek

Master

  • "jacek" is male

Posts: 2,729

Location: Warsaw, Poland

  • Send private message

9

Tuesday, June 7th 2005, 1:09pm

Quoted

Originally posted by Viro
That means that all the operations that apply to a vector, should apply to a 2D matrix too. Hence, I'm implementing it via inheritance.

Yes, but it also allows every row to have a different number of columns.

10

Tuesday, June 7th 2005, 2:18pm

OK... I'll give in. You're right that each row can then have different column lengths. I'll change the design.

But still, I'm curious to know why calling resize doesn't work. I mean in my second attempt, I tried to call vector<T>::resize(rows, vector<T>(cols, data)); but it didn't work. It said it couldn't find the resize method, eventhough resize is part of std::vector.

Anyone able to shed light on this?

jacek

Master

  • "jacek" is male

Posts: 2,729

Location: Warsaw, Poland

  • Send private message

11

Tuesday, June 7th 2005, 4:18pm

Quoted

Originally posted by Viro
It said it couldn't find the resize method, eventhough resize is part of std::vector.

Could you post what the compiler exacly said?

12

Tuesday, June 7th 2005, 10:21pm

This is what it says:
matrix.h:34: error: no matching function for call to 'CMatrix2D<double>::resize(int&, std::vector<double, std::allocator<double> >&)'

It complains about the following line this->resize:

Source code

1
2
3
4
5
6
template <typename T>
void CMatrix2D<T>::resize(int rows, int cols, T val) 
{	
	vector<T> v(cols,val);
	this->resize(rows, v);
}

jacek

Master

  • "jacek" is male

Posts: 2,729

Location: Warsaw, Poland

  • Send private message

13

Wednesday, June 8th 2005, 1:05am

Try this:

Source code

1
2
3
4
5
6
template <typename T>
void CMatrix2D<T>::resize(int rows, int cols, T val)
{
   vector<T> v(cols,val);
   vector< vector<T> >::resize(rows, v);
}

14

Wednesday, June 8th 2005, 9:09am

That works. Thanks.