-
August 24th, 2009, 07:47 AM
#1
Design problem with a virtual template class
Hi to all,
I'm new to this forum, nice to meet you.
Let me explain my problem: I am from Java. Yes, I know there is no cure for this but please be patient with me, I'm a Java programmer not due to my will.
Ok, I stop kidding, here it is my real problem:
I want to make a class which act as a Matrix for avoiding the direct use of multidimensional arraies. I've taken the example of the C++ Faq Lite but I wanted to make it more Object Oriented (at least this was mine intention).
So I made a template class Matrix and made it as pure virtual, then two implementation: ArrayMatrix and VectorMatrix (actually unimplemented), the first one use an array hidden in it and the second use a std::vector.
I stumbled in a great pain of compile errors and also many mistakes, after a week of yelling to my computer I found that templates and virtual functions cannot be combined.
Now my question is: can I make in some way a interface (which is pure virtual but not a template) and some implementations (which are templates) somehow?
More in depth:
As taken from the C++ Faq Lite I liked the idea to overload the operator() and at the beginning my code was something like this one (is incomplete an obliviously not functional):
[i]Matrix.h[7i]:
Code:
template<typename T> class Matrix {
public:
Matrix(unsigned int rows, unsigned int cols) throw (Eccezione)
: _righe(rows), _colonne(cols) {}
virtual ~Matrix();
virtual T& operator()(unsigned int row, unsigned int col) throw (Eccezione) = 0;
private:
const T& operator[](int);
protected:
unsigned int _righe;
unsigned int _colonne;
};
class BadSize : public Eccezione
{
public:
BadSize(const std::string& messaggio) : Eccezione(messaggio) {}
};
class IndexOutOfBound : public Eccezione
{
public:
IndexOutOfBound(const std::string& messaggio) : Eccezione(messaggio) {}
};
[i]Eccezione.h[7i]:
Code:
#include <exception>
#include <string>
using std::string;
class Eccezione : public std::exception {
public:
Eccezione();
Eccezione(const string& messaggio) : errore(messaggio) {}
~Eccezione() throw() {}
const char* what() const throw() { return errore.c_str(); }
protected:
string errore;
};
and one of my implementation, ArrayMatrix.h:
Code:
#include "Matrix.h"
template<typename T> class ArrayMatrix : public Matrix<T>
{
public:
ArrayMatrix(unsigned int rows, unsigned int cols) throw (Eccezione) : Matrix<T>(rows, cols)
{
if (rows == 0 || cols == 0)
throw BadSize("Impossile istanziare una Matrice di 0 righe o colonne.\n");
_data = new T[Matrix<T>::_righe * Matrix<T>::_colonne];
}
~ArrayMatrix()
{
delete[] _data;
}
T& operator()(unsigned int row, unsigned int col) throw (Eccezione)
{
if (row > Matrix<T>::_righe || col > Matrix<T>::_colonne)
throw IndexOutOfBound("Indice di riga o colonna non valido");
return _data[row * Matrix<T>::_colonne + col];
}
private:
T* _data;
};
I can't find a way to make an interface and then the implementation as a Matrix due to the redefinition of the operator().
If I remove the template from the class Matrix then the operator() will become:
Code:
virtual Matrix& operator()(unsigned int row, unsigned int col) throw (Eccezione) = 0;
isn't it?
But this will make the interface useless (because the implementations must return a Matrix class).
Am I wrong?
Is there an solutions or do I have to drop the interface and make every implementations as a solo class with no inheritance?
I hope I've been clear, forgive me for my English.
Thank you in advance for your replies.
-
August 24th, 2009, 09:09 AM
#2
Re: Design problem with a virtual template class
Originally Posted by BlueAngelTC
Hi to all,
I stumbled in a great pain of compile errors and also many mistakes, after a week of yelling to my computer I found that templates and virtual functions cannot be combined.
I am not too sure I understand, my understanding is that templates and virtual functions can be combined, shown below is a small example (correct me if I am wrong):
Code:
#include <iostream>
template<typename T>
class ClassA
{
public:
virtual void f1() = 0;
};
template<typename T>
class ClassB : public ClassA<T>
{
public:
void f1();
};
template<typename T>
void ClassB<T> :: f1() //Generic Implementation
{
std :: cout << "ClassB<T> :: f1() invoked\n";
}
template<> //Specialized for double
void ClassB<double> :: f1()
{
std :: cout << "ClassB<double> :: f1() invoked\n";
}
int main()
{
system("clear");
ClassB<int> objB1;
ClassA<int> *ptrA1 = &objB1;
ptrA1 -> f1();
ClassB<double> objB2;
ClassA<double> *ptrA2 = &objB2;
ptrA2 -> f1();
return(0);
}
Last edited by Muthuveerappan; August 24th, 2009 at 09:16 AM.
Reason: modified code to show specializing the template for a specific type
-
August 24th, 2009, 09:23 AM
#3
Re: Design problem with a virtual template class
You can't have a non-template member function returning a value that depends on the type used in the template class that it inherits from. How would it know the type?
A quick play with the code shows that your basic template idea works.
Code:
#include <vector>
template <typename T>
class Matrix
{
public:
Matrix(unsigned int rows, unsigned int cols)
: _righe(rows), _colonne(cols) {}
virtual ~Matrix() = 0
{
}
virtual T& operator()(unsigned int row, unsigned int col) = 0;
private:
const int& operator[](int);
protected:
unsigned int _righe;
unsigned int _colonne;
};
template<typename T>
class ArrayMatrix : public Matrix<T>
{
public:
ArrayMatrix(unsigned int rows, unsigned int cols) : Matrix<T>(rows, cols)
{
_data = new T[_righe * _colonne];
}
~ArrayMatrix()
{
delete[] _data;
}
T& operator()(unsigned int row, unsigned int col)
{
return _data[row * _colonne + col];
}
private:
T* _data;
};
template<typename T>
class VectorMatrix : public Matrix<T>
{
public:
VectorMatrix(unsigned int rows, unsigned int cols) : Matrix<T>(rows, cols)
{
_data.resize(_righe * _colonne);
}
~VectorMatrix()
{
}
T& operator()(unsigned int row, unsigned int col)
{
return _data[row * _colonne + col];
}
private:
std::vector<T> _data;
};
int main()
{
ArrayMatrix<int> array_matrix(10, 20);
array_matrix(2, 4) = 1;
VectorMatrix<int> vector_matrix(10, 20);
vector_matrix(2, 4) = 2;
Matrix<int> *p_matrix = &array_matrix;
int value = (*p_matrix)(2, 4); // value = 1
p_matrix = &vector_matrix;
value = (*p_matrix)(2, 4); // value = 2
}
You'll need to create const versions of the operators too.
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
Richard P. Feynman
-
August 24th, 2009, 10:17 AM
#4
Re: Design problem with a virtual template class
I'm a bit confused JohnW,
thank you for your reply but your code won't even compile. As mine it won't for the same reason: a template function cannot be virtual.
The operator() in Matrix is a template because the entire class is a template (correct me if I'm wrong).
(so your code will generate my same error: undefined reference to Matrix.h)
My problem is I cannot make the class Matrix as a template because it's is an interface (a pure virtual class) but I need that the implementation should be a template.
A solution, if I still wish to keep the interface, is to make the interface and the implementation to return a pointer to void (and so return everything I wish) but this solution is too ugly for me.
The other one is to drop the Matrix class avoiding inheritance, same uglyness as above.
Or maybe there is some trick and I can still keep the interface but actually I don't know how. That's my question: how can I keep the interface and having the implementation a template, if possible?
@Muthuveerappan, yes they cannot be combined, so the question is the above one.
By the way, JohnW, there are two mistakes in your code, maybe you didn't notice:
The pure virtual destructor in Matrix have an (empy) implementation, it should only be declared.
Also ArrayMatrix cannot access to protected variables _righe and _colonne ("rows" and "columns" in English, sorry I left the names in Italian) directly, it must use the Matrix<T>:: sintax.
Forgive me: I forgot to put the error the compiler give me when I use this code. Anyway it give a generic "undefined reference" to the Matrix class (it produce an error for every function of this class).
-
August 24th, 2009, 10:27 AM
#5
Re: Design problem with a virtual template class
@Muthuveerappan
My apologize, I've read wrong your reply. (I read "they cannot" instead of "they can").
No, as far I found on Internet (and the error gcc give me) they cannot combined.
And also you make a specialization of the template... this is useless for me.
I need a matrix an it doesn't know what will be stored in his buffer (which can be an array, a vector or anything else). That's why I used a template: because only who will use my implementations know what to put inside the buffer.
If I have to specialize every function each time I have to use the matrix with a different class then templates are useless (in this case).
Specialization should be use for specific case but templates are made for generic use.
As told you I'm from Java but Java do everything at run-time (and in fact it's deadly slow), C++ do everything statically, ok: I understand this. But the purpose of the template should be that you don't know a priori what class you'll use with them.
-
August 24th, 2009, 10:42 AM
#6
Re: Design problem with a virtual template class
@Muthuveerappan
Ok, now I'm really confused: your code compile and work O_o
I thought, as I've read since now, that templates cannot be virtual... so if this can be possibile what's wrong with my code?
That's the error I get:
Code:
Building target: testVari
Invoking: GCC C++ Linker
g++ -o"testVari" ./src/ArrayMatrix.o ./src/TestSingleton.o ./src/VectorMatrix.o ./src/mah.o ./src/testVari.o
./src/testVari.o: In function `main':
/mnt/data/opt/workspace/testVariC++/Debug/../src/testVari.cpp:40: multiple definition of `main'
./src/mah.o:/mnt/data/opt/workspace/testVariC++/Debug/../src/mah.cpp:24: first defined here
./src/testVari.o: In function `ArrayMatrix<int>::~ArrayMatrix()':
testVari.cpp:(.text._ZN11ArrayMatrixIiED0Ev[ArrayMatrix<int>::~ArrayMatrix()]+0x2e): undefined reference to `Matrix<int>::~Matrix()'
./src/testVari.o: In function `ArrayMatrix<int>::~ArrayMatrix()':
testVari.cpp:(.text._ZN11ArrayMatrixIiED1Ev[ArrayMatrix<int>::~ArrayMatrix()]+0x2e): undefined reference to `Matrix<int>::~Matrix()'
./src/testVari.o: In function `ArrayMatrix<int>::ArrayMatrix(unsigned int, unsigned int)':
testVari.cpp:(.text._ZN11ArrayMatrixIiEC1Ejj[ArrayMatrix<int>::ArrayMatrix(unsigned int, unsigned int)]+0x62): undefined reference to `Matrix<int>::~Matrix()'
collect2: ld returned 1 exit status
-
August 24th, 2009, 10:48 AM
#7
Re: Design problem with a virtual template class
Originally Posted by BlueAngelTC
I'm a bit confused JohnW,
thank you for your reply but your code won't even compile.
Which compiler are you using? It compiles and runs fine on mine (Visual Studio 2008).
By the way, JohnW, there are two mistakes in your code, maybe you didn't notice:
The pure virtual destructor in Matrix have an (empy) implementation, it should only be declared.
Not exactly an error. It's just saying that you MUST override the destructor, but also defines the base destructor code. A bit pointless I know, as it doesn't actually do anything. It was just a leftover from my experiment. A pure virtual destructor, with a default implementation, is sometimes a valid thing to do.
Also ArrayMatrix cannot access to protected variables _righe and _colonne ("rows" and "columns" in English, sorry I left the names in Italian) directly, it must use the Matrix<T>:: sintax.
A derived class can access protected members of the class it's derived from. That's the difference between protected and private.
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
Richard P. Feynman
-
August 24th, 2009, 10:57 AM
#8
Re: Design problem with a virtual template class
Actually I take back that bit about the protected members.
Pasting the code into Comeau online compiler shows that the variables need to be qualified when using templates.
This passes Comeau.
Code:
#include <vector>
template <typename T>
class Matrix
{
public:
Matrix(unsigned int rows, unsigned int cols)
: _righe(rows), _colonne(cols) {}
virtual ~Matrix() = 0;
virtual T& operator()(unsigned int row, unsigned int col) = 0;
private:
const int& operator[](int);
protected:
unsigned int _righe;
unsigned int _colonne;
};
template<typename T>
class ArrayMatrix : public Matrix<T>
{
public:
ArrayMatrix(unsigned int rows, unsigned int cols) : Matrix<T>(rows, cols)
{
_data = new T[Matrix<T>::_righe * Matrix<T>::_colonne];
}
~ArrayMatrix()
{
delete[] _data;
}
T& operator()(unsigned int row, unsigned int col)
{
return _data[row * Matrix<T>::_colonne + col];
}
private:
T* _data;
};
template<typename T>
class VectorMatrix : public Matrix<T>
{
public:
VectorMatrix(unsigned int rows, unsigned int cols) : Matrix<T>(rows, cols)
{
_data.resize(Matrix<T>::_righe * Matrix<T>::_colonne);
}
~VectorMatrix()
{
}
T& operator()(unsigned int row, unsigned int col)
{
return _data[row * Matrix<T>::_colonne + col];
}
private:
std::vector<T> _data;
};
int main()
{
ArrayMatrix<int> array_matrix(10, 20);
array_matrix(2, 4) = 1;
VectorMatrix<int> vector_matrix(10, 20);
vector_matrix(2, 4) = 2;
Matrix<int> *p_matrix = &array_matrix;
int value = (*p_matrix)(2, 4);
p_matrix = &vector_matrix;
value = (*p_matrix)(2, 4);
}
"It doesn't matter how beautiful your theory is, it doesn't matter how smart you are. If it doesn't agree with experiment, it's wrong."
Richard P. Feynman
-
August 24th, 2009, 11:08 AM
#9
Re: Design problem with a virtual template class
I use GCC on Linux.
I know a derived class can access protected members, that's the reason _righe and _colonne are protected and not private.
But.. http://www.parashift.com/c++-faq-lit...html#faq-35.18 as I know it's the way the standard comitee suggest to do.
In fact if I use a protected data member from a template class directly, gcc give me an error (it will not if the base class is not a template one).
Anyway Comeau, as I've read, is a good compiler. It even support the export keyword. But this is not standard code, I need the code to be portable: it have to run both on GCC and other compilers.
As I wrote in my last post seems that Muthuveerappan is right and templates can be virtuals, if so I made some other mistakes on my code.
Tomorrow I will look for the ISO specification of C++ for confirmations about this fact.
But I still need the code to work...
-
August 24th, 2009, 01:46 PM
#10
Re: Design problem with a virtual template class
Originally Posted by BlueAngelTC
I use GCC on Linux.
What version of GCC? That compiler has gone through many revisions, so you need to specify exactly which version of the compiler you're using.
Anyway Comeau, as I've read, is a good compiler. It even support the export keyword. But this is not standard code,
The export keyword is standard -- the issue is that very few compilers support it right now.
Regards,
Paul McKenzie
-
August 24th, 2009, 01:59 PM
#11
Re: Design problem with a virtual template class
I use gcc version 4.0.1 (Apple Inc. build 5488)
Could you provide a simple (bare minimum) application file that uses the header file and so that we can compile and see which one you are referring to.
Just a small suggestion I find the below mentioned usually convenient:
1) writing a small piece of code with basic functionality, compiling and running it, only if everything is ok, then I build on it. That way it helps a bit (this is my view) instead of clearing all the errors at the end and cud means re-work as well
2) since it is your program, you would have spent time on it, instead of posting the entire program, you can just create a bare minimum code (indicating only the problematic area), that way it would be a touch simpler to debug, that way u wud have isolated the problem to some extent.
Changes I made :
-----------------------
1) since the destructor wasn't built I just put a dummy destructor implementation to get rid of the linker error.
my application file looks like this (which works ok):
Provide ur application file (just the bare minimum) indicating the problematic area.
Code:
int main()
{
ArrayMatrix<int> m1(1, 2);
return(0);
}
Also note, with multiple files you also need to consider makefile if u r doing it manually.
Last edited by Muthuveerappan; August 24th, 2009 at 02:04 PM.
-
August 25th, 2009, 02:33 AM
#12
Re: Design problem with a virtual template class
Thank you very much for your replies guys.
I found what's the real problem: the destructor in the class Matrix is pure virtual, making it just virtual and giving him an (empty) definition the code works.
I found this link: http://www.devx.com/tips/Tip/12729 which basically say that a destructor can be pure virtual but still must be defined.
It was my mistake, I was blind as always.
I will keep coding this way.
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|