Reputation: 59
I'm student in my final year for my masters degree in computer graphics we had to do an exercise in C++.
Here is the code :
AbsMatrice.h
:
#pragma once
template<int M,int N, typename T>
class AbsMatrice
{
private:
T m_data[M][N];
public:
AbsMatrice();
~AbsMatrice();
AbsMatrice<M, N, T> mul(AbsMatrice<M,N,T> &a);
AbsMatrice<M, N, T> add(AbsMatrice<M, N, T> &a);
void read(...);
T& at(int row, int col);
T& operator ()(int row, int col);
//fonction virtuelle pure
virtual void print() = 0;
int& getNumRows(){ return M; }
int& getNumColumns(){ return N; }
};
Matrice.h
:
#pragma once
#include "AbsMatrice.h"
template <int M, int N, typename T>
class Matrice : public AbsMatrice<M,N,T>
{
public:
Matrice();
~Matrice();
void print();
};
AbsMatrice.cpp
:
#include "AbsMatrice.h"
#include <iostream>
template<int M, int N, typename T>
AbsMatrice<M, N, T>::AbsMatrice(){
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
m_data[i][j] = 0;
}
}
}
template<int M, int N, typename T>
AbsMatrice<M, N, T>::~AbsMatrice()
{
}
template<int M, int N, typename T>
T& AbsMatrice<M, N, T>::operator ()(int row, int col)
{
return m_data[row][col];
}
template<int M, int N, typename T>
T& AbsMatrice<M, N, T>::at(int row, int col)
{
return m_data[row][col];
}
template<int M, int N, typename T>
AbsMatrice<M, N, T> AbsMatrice<M, N, T>::add(AbsMatrice<M, N, T> &a)
{
if (this->getNumColumns() == a.getNumColumns() && this->getNumRows() == a.getNumRows())
{
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
m_data[i][j] += a(i, j);
}
}
}
else
std::cout << "Erreur matrice de taille différentes !" << std::endl;
return this;
}
template<int M, int N, typename T>
void AbsMatrice<M, N, T>::print()
{
std::cout << "la matrice :" << std::endl;
}
Matrice.cpp
:
#include "Matrice.h"
#include <iostream>
template <int M, int N, typename T>
Matrice<M,N,T>::~Matrice()
{
}
template <int M, int N, typename T>
void Matrice<M, N, T>::print()
{
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
std::cout << " " << this->m_data[i][j] << " ";
}
std::endl;
}
}
when I try to do this in main:
main.cpp:
#include "Matrice.h"
int main()
{
Matrice<2,2,int> a;
Matrice<2,2,int> b;
}
I get a nasty:
error C2259: 'AbsMatrice<2,2,T>' : cannot instantiate abstract class
1> with
1> [
1> T=int
1> ]
1> due to following members:
1> 'void AbsMatrice<2,2,T>::print(void)' : is abstract
1> with
1> [
1> T=int
1> ]
1> c:\users\bobmaza\documents\visual studio 2013\projects\tpmatrices\tpmatrices\absmatrice.h(22) : see declaration of 'AbsMatrice<2,2,T>::print'
1> with
1> [
1> T=int
1> ]
I tried searching everywhere on the web , but did not find a case close to mine and most of the guys did not use the same signature to override the abstract function, but it is not my case. I never seen an error like this thank you in advance.
What is the meaning of the error message and how to correct it?
Note: I have been coding in c++ in several years but never had to do something like this , so I can't figure it out !
P.S. : Sorry for the French names I'm a student in France.
EDIT : thanks to everyone for the help , first time i HAD to ask arround here , great community !
Upvotes: 1
Views: 71
Reputation: 46
The compiler tells you exactly what is happening - void Matrice<M,N,T>::print()
is not declared virtual
thus leading to pure virtual function virtual void print() = 0
not to be overloaded.
To avoid this in future, specify the overloading (virtual) functions as override
.
Moreover, I assume the print
function to not modify the internal state of the object and to work all the time, so the const noexcept
specifier would be appropriate.
Here is a snippet which might help you with the safer virtual functions overloading
class Interface
{
public:
virtual ~Interface() {}
virtual void print() const noexcept = 0;
};
class Implementation : public Interface
{
public:
virtual ~Implementation() {}
virtual void print() const noexcept override
{
...
}
};
throw specifier
is declared in the overloading function, the
error is fired.internal state specifier
is declared
in the overloading function, the error is fired.overriding
function does not override, the error is fired.Upvotes: 0
Reputation: 42899
First of, since AbsMatrice
is pure virtual you can't return by value an abstract type, so you must return either a reference or pointer:
AbsMatrice<M, N, T>& mul(AbsMatrice<M, N, T> &a);
^
AbsMatrice<M, N, T>& add(AbsMatrice<M, N, T> &a);
^
Secondly, destructor of a base class must be declared virtual
to avoid potentially memory leaks.
virtual ~AbsMatrice();
Upvotes: 0
Reputation: 11513
Templates must always be completely defined, as the compiler will generate an implementation whenever a template is instantiated, with the concrete template parameters specified. Therefore, all method bodies must be available wherever a template is used.
That's why template classes / libraries are often contained in a single .hpp
file.
What does this mean for your case? Even if there is a template implementation for Matrice<int,int,typename>::print()
in some .cpp
file, the compiler does not see it when compiling main.cpp
. Therefore it cannot generate an implementation for Matrice<2,2,int>::print()
, and thus, there is no definition of that method. All it sees is virtual AbsMatrice::print() = 0;
Upvotes: 0
Reputation: 97571
You need to define your function, not just declare it:
virtual void print() {}
Upvotes: 1