首页 > 解决方案 > 关于真正使用抽象类的问题

问题描述

我正在编写程序来处理不同类型的矩阵,例如稀疏矩阵等。现在我有一个称为 DOK 的矩阵类型的完整类,并决定我需要一个抽象类 Matrix 以在其他子矩阵中继承,并且我将能够应用所有具有不同类的虚拟操作。所以我做了 Base 类

#include "Triplet.h"
#include <iostream>
using namespace std;
template<typename T>
class Matrix{
public:
    virtual Matrix<T>& operator*=(const Matrix<T>& B) = 0;

    virtual const Matrix<T>& operator*(const Matrix<T>& B) const = 0;

    virtual Matrix<T>& operator-=(const Matrix<T>& B) = 0;

    virtual const Matrix<T>& operator-(const Matrix<T>& B) const = 0;

    virtual Matrix<T>& operator+=(const Matrix<T>& B) = 0;

    virtual const Matrix<T>& operator+(const Matrix<T>& B) const = 0;

    virtual T operator()(int i, int j) = 0;

    virtual T operator()(int i, int j) const = 0;

    [[nodiscard]] virtual int getSizeN() const = 0;

    [[nodiscard]] virtual int getSizeM() const = 0;

    [[maybe_unused]] virtual void insert(const Triplet<T> &Element) = 0;
    [[maybe_unused]] virtual void print() const = 0;
};
template<typename  T>
ostream& operator<<(ostream &os, const Matrix<T>& matrix) {
    matrix.print();
    return os;
}

Triplet.h是结构

template<typename T>
struct Triplet{
    int i;
    int j;
    T b;
};

选项卡是

template<typename T>
T Tabs(T num){
    if(num<T(0)) return -num;
    else return num;
}

和子类 DOK

#include "Matrix.h"
#include <map>
#include <iostream>
#include <vector>
#include <iterator>
#include "Triplet.h"
//#include "Solver.h"
#include "Tabs.h"
#include "cmath"
#include "gnuplot-iostream.h"
#include <utility>
using namespace std;
template<typename T>
T tolerance = T(1e-19);

template<typename T>
class DOK: public Matrix<T>{
private:
    /*
     * Dictionary of Keys, pair<int, int> is coordinates of non-zero elements,
     * next int is value
     */

    int size_n;
    int size_m;
    map<pair<int, int>, T> dict;
    // int count;
public:

    DOK(vector<Triplet<T>> &matrix, int n, int m){
        this->resize(n, m);
        this->fill(matrix);
    }

    DOK(int n, int m){
        this->resize(n, m);
    }
    ~DOK() = default;

    void 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]);
        }
    }

    void insert(const Triplet<T> &Element) override{
        if(Element.i >= this->size_n){
            this->size_n = Element.i+1;
        }
        if(Element.j >= this->size_m){
            this->size_m = Element.j+1;
        }
        pair<int, int> coordinates = {Element.i, Element.j};
        this->dict.insert(pair(coordinates, Element.b));
    }

    void resize(int n, int m){
        this->size_n=n;
        this->size_m=m;
    }
    void print() const override {
        cout<<endl;
        for(int i = 0; i < this->size_n; i++){
            for(int j = 0; j < this->size_m; j++){
                if(this->dict.find({i, j})!= this->dict.cend()) cout<< fixed << setprecision(18)<<this->dict.find(pair(i, j))->second<<" "; else cout<<0<<" ";
            }
            cout<<endl;
        }
    }

    void clearZeros(){
        for(auto i = this->dict.begin(); i!=this->dict.end();){
            if(Tabs(i->second) <=  tolerance<T>){
                i = this->dict.erase(i);
            } else{
                i++;
            }
        }
    }

    [[nodiscard]] int getSizeN() const override{
        return this->size_n;
    }

    [[nodiscard]] int getSizeM() const override{
        return this->size_m;
    }
    void clearZeros(){
        for(auto i = this->dict.begin(); i!=this->dict.end();){
            if(Tabs(i->second) <=  tolerance<T>){
                i = this->dict.erase(i);
            } else{
                i++;
            }
        }
    }

    DOK<T>& operator+=(const Matrix<T> &matrix) override {
        try{
            if(this->getSizeN() != matrix.getSizeN() || this->getSizeM() != matrix.getSizeM()) throw 1;
            for(int i = 0; i < this->getSizeN(); i++) {
                for (int j = 0; j < this->getSizeM(); j++) {
                    T c = this->operator()(i, j) + matrix(i, j);
                    if(Tabs(c) > tolerance<T>) this->insert({i, j, c}); else this->dict.erase({i, j});
                }
            }
            return *this;
        }
        catch (int a) {
            cout<<"Sizes of Matrices are different."<<endl;
        }
    }

    const DOK<T>& operator+(const Matrix<T>& matrix) const override {
        DOK<T> t = *this;
        return move(t+=matrix);
    }

    DOK<T>& operator-=(const Matrix<T>& matrix) override {
        try{
            if(this->getSizeN() != matrix.getSizeN() || this->getSizeM() != matrix.getSizeM()) throw 1;
            for(int i = 0; i < this->getSizeN(); i++) {
                for (int j = 0; j < this->getSizeM(); j++) {
                    T c = this->operator()(i, j) - matrix(i, j);
                    if(Tabs(c) > tolerance<T>) this->insert({i, j, c}); else this->dict.erase({i, j});
                }
            }
            return *this;
        }
        catch (int a) {
            cout<<"Sizes of Matrices are different."<<endl;
        }
    }

    const DOK<T>& operator-(const Matrix<T> &matrix) const override {
        DOK<T> t = *this;
        return move(t-=matrix);
    }

    DOK<T>& operator*=(const Matrix<T> &matrix) override {
        try {
            if(this->getSizeN() != matrix.getSizeN()) throw 1;
            DOK<T> M = DOK(this->getSizeN(), matrix.getSizeM());
            for (int i = 0; i < this->getSizeN(); i++) {
                for (int j = 0; j < matrix.getSizeM(); j++) {
                    T a=0;
                    for(int k = 0; k<this->getSizeM(); k++){
                        if(this->operator()(i, k) != 0 && matrix(k, j) != 0){
                            a+=this->operator()(i, k)*matrix(k,j);
                            //cout<<a<<endl;
                        }
                    }
                    Triplet<T> m = {i, j, a};
                    M.insert(m);
                }
            }
            this->clearZeros();
            *this=M;
            return *this;
        }
        catch (int a) {
            cout<<"Wrong sizes of matrices to multiplication"<<endl;
        }
    }

    const DOK<T>& operator*(const Matrix<T>& matrix) const override{
        DOK<T> t = *this;
        return t*=matrix;
    }
    T operator()(int row, int col) override{
        if(this->dict.find({row, col}) != dict.end()) return this->dict.find({row, col})->second;
        else return T(0);
    }

    T operator()(int row, int col) const override{
        if(this->dict.find({row, col}) != dict.end()) return this->dict.find({row, col})->second;
        else return T(0);
    }
};

但是我遇到了一个问题,现在我无法创建 DOK 对象,因为 Matrix 是一个抽象类。所以如果我这样做了

DOK<double> Q = DOK<double>(...)
cout<<Q*Q;

它正在工作,但现在我不能这样做,一种可能的变体是取消引用指针

Matrix<double>* Q = new DOK<double>(...);
cout<<(*Q) * (*Q);

如何在不从指针引用重写代码的情况下修复它?

标签: c++inheritancematrixabstract-class

解决方案


推荐阅读