Design problem with a virtual template class
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12

Thread: Design problem with a virtual template class

  1. #1
    Join Date
    Aug 2009
    Posts
    11

    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.

  2. #2
    Join Date
    Feb 2009
    Posts
    326

    Re: Design problem with a virtual template class

    Quote Originally Posted by BlueAngelTC View Post
    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

  3. #3
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,725

    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

  4. #4
    Join Date
    Aug 2009
    Posts
    11

    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).

  5. #5
    Join Date
    Aug 2009
    Posts
    11

    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.

  6. #6
    Join Date
    Aug 2009
    Posts
    11

    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

  7. #7
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,725

    Re: Design problem with a virtual template class

    Quote Originally Posted by BlueAngelTC View Post
    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

  8. #8
    Join Date
    Jul 2002
    Location
    Portsmouth. United Kingdom
    Posts
    2,725

    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

  9. #9
    Join Date
    Aug 2009
    Posts
    11

    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...

  10. #10
    Join Date
    Apr 1999
    Posts
    27,434

    Re: Design problem with a virtual template class

    Quote Originally Posted by BlueAngelTC View Post
    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

  11. #11
    Join Date
    Feb 2009
    Posts
    326

    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.

  12. #12
    Join Date
    Aug 2009
    Posts
    11

    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
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center