Проблема с реализацией абстрактного класса С++

Имею абстрактный класс

template<typename T>
struct Triplet{
   int i;
   int j;
   T b;
};
template<typename T>
class Matrices
{
public:
   // Виртуальный деструктор
   virtual ~Matrices() = 0;
   /*
    * Виртуальные методы, должны быть реализованы вашим классом
    */
   virtual void fill(vector<Triplet<T>> &matrix) = 0;
   virtual const Matrices<T> operator+(const Matrices<T> &matrix) const = 0;
   virtual const Matrices<T> operator-(const Matrices<T> &matrix) const = 0;
   virtual const Matrices<T> operator*(const Matrices<T> &matrix) const = 0;
   virtual const Matrices<T> operator*(T& k) const = 0;
   virtual const Matrices<T> operator*(const T& k) const = 0;
   virtual T& operator()(int row, int col) = 0;
   virtual const T& operator()(int row, int col) const = 0;
};

Наследую его в своем классе

template<typename T>
class DOK: public Matrices<T>{
private:
    /*
     * Dictionary of Keys, pair<int, int> is coordinates of non-zero elements,
     * next int is value
     */
    map<pair<int, int>, T> dict;
    int size_n;
    int size_m;
   // int count;
public:

    DOK(vector<Triplet<T>> &matrix, int n, int m);
    DOK(int n, int m);
    ~DOK(){};
    void fill(vector<Triplet<T>> &matrix);
    void insert(const Triplet<T> &Element);
    void resize(int n, int m);
    void print() const;


    const DOK<T> operator+(const DOK<T> &matrix) const;
    const DOK<T> operator-(const DOK<T> &matrix) const;
    const DOK<T> operator*(const DOK<T> &matrix) const;
    const DOK<T> operator*(T& k) const;
    const DOK<T> operator*(const T& k) const;

    T& operator()(int row, int col);
    const T& operator()(int row, int col) const;
};

template<typename T>
void operator+=(DOK<T>& left, const DOK<T>& right){
    left=left+right;
}
template<typename  T>
void operator-=(DOK<T>& left, const DOK<T>& right){
    left = left - right;
}
template<typename  T>
void operator*=(DOK<T>& left, const DOK<T>& right){
    left = left * right;
}
template<typename  T>
void operator*=(DOK<T>& left, T& k){
    left = left*k;
}
template<typename  T>
void operator*=(DOK<T>& left,const T& k){
    left = left*k;
}

template<typename  T>
const DOK<T> operator*(T& k, const DOK<T> &matrix){
    return matrix*k;
}
template<typename  T>
const DOK<T> operator*(const T& k, const DOK<T> &matrix){
    return matrix*k;
}

template<typename  T>
ostream& operator<<(ostream &os, const DOK<T> &matrix){
    matrix.DOK<T>::print();
    return os;
}

Реализация:

template<typename  T>
DOK<T>::DOK(int n, int m){
    this->resize(n, m);
}
template<typename  T>
DOK<T>::DOK(vector<Triplet<T>> &matrix, int n, int m) {
    //cout<<"Input height and weight of matrix: "<<endl;
    //cin>>n>>m;
    this->resize(n, m);
    this->fill(matrix);
}
template<typename  T>
void DOK<T>::fill(vector<Triplet<T>> &matrix) {
    //this->count=matrix.size();
    //cout<<"Input your coordinates with value in format \"i j val\" "<<endl;
    for(int k = 0; k < matrix.size(); k++){
        this->insert(matrix[k]);
    }
}
/*
 * Inserts element with coordinates i, j and value b in matrix
 */
template<typename  T>
void DOK<T>::insert(const Triplet<T> &Element){
    try {
        if(Element.i > this->size_n || Element.j > size_m) throw 1;
        pair<int, int> coordinates = {Element.i, Element.j};
        this->dict.insert(make_pair(coordinates, Element.b));
    }
    catch (int a) {
        cout<<"Inserting coordinates {"<<Element.i<<", "<<Element.j<<"} out of range. "<<endl;
    }
}
template<typename  T>
void DOK<T>::resize(int n, int m){
    this->size_n=n;
    this->size_m=m;
}
template<typename  T>
const DOK<T> DOK<T>::operator+(const DOK<T> &matrix) const{
    try{
        if(this->size_n != matrix.size_n || this->size_m != matrix.size_m) throw 1;
        DOK<T> M = *this;
        for(auto j: matrix.dict){
            if(M.dict.find(j.first)!=M.dict.cend()) {
                M.dict[j.first] += j.second;
            }else{
                M.dict.insert({j.first, j.second});
                //M.count++;
            }
        }
        return M;
    }
    catch (int a) {
        cout<<"Sizes of Matrices are different."<<endl;
    }
}
template<typename  T>
const DOK<T> DOK<T>::operator-(const DOK<T> &matrix) const{
    return -1.*matrix+*this;
}
template<typename  T>
 void DOK<T>::print() const {
    cout<<endl;
    for(int i = 1; i <= this->size_n; i++){
        for(int j = 1; j <= this->size_m; j++){
            if(this->dict.find({i, j})!= this->dict.cend()) cout<<this->dict.find(make_pair(i, j))->second<<" "; else cout<<0<<" ";
        }
        cout<<endl;
    }
}



template<typename  T>
const DOK<T> DOK<T>::operator*(const DOK<T> &matrix) const{
    try {
        if(this->size_m != matrix.size_n) throw 1;
        DOK<T> M = DOK(this->size_n, matrix.size_m);
        for (int i = 1; i <= this->size_n; i++) {
            for (int j = 1; j <= matrix.size_m; j++) {
                T a=0;
                for(int k = 1; k<=this->size_m; k++){
                    if(this->dict.find({i,k}) != this->dict.cend() && matrix.dict.find({k, j})!=matrix.dict.cend()){
                        a+=this->dict.find({i,k})->second*matrix.dict.find({k,j})->second;
                        //cout<<a<<endl;
                    }
                }
                Triplet<T> m = {i, j, a};
                M.insert(m);
            }
        }
        return M;
    }
    catch (int a) {
        cout<<"Wrong sizes of matrices to multiplication"<<endl;
    }
}

template<typename  T>
const DOK<T> DOK<T>::operator*(T& k) const{
    DOK<T> M = *this;
    for(auto i: M.dict){
        M.dict[i.first]*=k;
    }
    return M;
}
template<typename  T>
const DOK<T> DOK<T>::operator*(const T& k) const{
    DOK<T> M = *this;
    for(auto i: M.dict){
        M.dict[i.first]*=k;
    }
    return M;
}

template<typename  T>
 T& DOK<T>::operator()(int row, int col){
    return this->dict.find({row, col})->second;
}
template<typename  T>
const T& DOK<T>::operator()(int row, int col) const{
    return this->dict.find({row, col})->second;
}

В итоге при попытке создания на стеке экземпляра дочернего класса DOK получаю такую ошибку, будто бы реализаций трех чисто виртуальных методов нет

DOK<double> p = DOK<double>(in, 3, 3);
Allocating an object of abstract class type 'DOK<double>'
unimplemented pure virtual method 'operator+' in 'DOK'
unimplemented pure virtual method 'operator-' in 'DOK'
unimplemented pure virtual method 'operator*' in 'DOK'

In instantiation of template class 'DOK<double>' virtual function 'operator*' has a different return type ('const DOK<double>') than the function it overrides (which has return type 'const Matrices<double>')

Никак не могу найти проблему, помогите пожалуйста


Ответы (1 шт):

Автор решения: AR Hovsepyan

Первая проблема:

  • Вы пытаетесь возвращать объект(не ссылку и не указатель) абстрактного класса из операторов. Объект абстрактного класса невозможно создать, следовательно не возможно вернуть такой объект из какой либо функции.

Вторая проблема:

  • Абстрактные классы предназначены для обеспечения интерфейсом (возможно и некоторыми данными) своим производным классам и возможности написать рудиментарный код, не зависящий от того, объект какого производного класса участвует. Поэтому, для данного случая, написанный абстрактный класс не имеет никакого смысла, если даже исправить все ошибки.

Третья проблема:

  • Производные классы должны переопределить все чистые виртуальные функции абстрактного класса точно с таким же набором аргументов и возвращаемого типа, что объявлено в абстрактном классе, иначе функция_член не определена, и этот производный класс сам является абстрактным.

Если вы хотите все же исправить, а не написать без базового класса, то покажу на одном операторе.

template<typename T>
class Matrices
{
    //...
public:
    // Виртуальный деструктор
    virtual ~Matrices() = 0;
    //...
    //сначала определим +=, чтобы возвращать ссылку, а не другой объект
    virtual  Matrices<T>& operator+=(const Matrices<T>&)  = 0;   
};

template<typename T>
class DOK : public Matrices<T> {
private:
    /*  
     ...
     */
public:
    //...
    /*ключевое слово override подсказывает компилятору, что пытаемся
     переопределять член базового класса. Компилятор сам проверит сигнатуру функции
     и в случаи ошибки, сообщит об этом*/
    Matrices<T>& operator+=(const Matrices<T>&)   override
    {
        // ваш код
        return *this;
    }
    //теперь можно написать и оператор +, что принадлежит только этому классу
    const DOK<T> operator+(const DOK<T>& d) const
    {
        DOK<T> t;
        return t += d;
    }
};

Или можете написать независимый шаблон оператора, чтобы использовать для любого типа:

 template<class M>
 const M operator+(const M& m) const
 {
    M t;
    return t += m;
 }
→ Ссылка