c++模板抽象继承

c++ template abstract inheritance

本文关键字:继承 抽象 c++      更新时间:2023-10-16

我是计算机图形学硕士学位最后一年的学生,我们必须用C++做一个练习。

这是代码:

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;
    }
}

当我主要尝试这样做时:

main.cpp:

#include "Matrice.h"

int main()
{
    Matrice<2,2,int> a;
    Matrice<2,2,int> b;
}

我得到了一个讨厌的:

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:usersbobmazadocumentsvisual studio 2013projectstpmatricestpmatricesabsmatrice.h(22) : see declaration of 'AbsMatrice<2,2,T>::print'
1>          with
1>          [
1>              T=int
1>          ]

我试着在网上到处搜索,但没有找到与我相似的案例,大多数人也没有使用相同的签名来覆盖抽象函数,但我的情况并非如此。我从来没有见过这样的错误,提前谢谢你。

错误消息的含义是什么?如何更正?

注意:我已经用c++编程好几年了,但从来没有做过这样的事情,所以我想不通!

附言:对不起,我是在法国的学生。

编辑:感谢大家的帮助,我第一次不得不在这里请求阿伦,伟大的社区!

您需要定义您的函数,而不仅仅是声明它:

virtual void print() {}

编译器告诉发生了什么-void Matrice<M,N,T>::print()没有声明为virtual,因此导致纯虚拟函数virtual void print() = 0不会过载

为了避免将来出现这种情况,请将重载(虚拟)函数指定为override

此外,我假设print函数不修改对象的内部状态,并一直工作,因此const noexcept说明符是合适的。

以下是一个片段,它可能会帮助您实现更安全的虚拟函数重载

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时错误被激发
  • 当声明较宽松的internal state specifier时在重载函数中,会触发错误
  • overriding函数不覆盖,则会触发错误

模板必须始终完全定义,因为无论何时实例化模板,编译器都会生成一个实现,并指定具体的模板参数。因此,无论在哪里使用模板,所有方法体都必须可用。这就是为什么模板类/库通常包含在单个.hpp文件中。

这对你的案子意味着什么?即使在某些.cpp文件中有Matrice<int,int,typename>::print()的模板实现,编译器在编译main.cpp时也看不到它。因此,它无法生成Matrice<2,2,int>::print()的实现,因此,没有该方法的定义。它看到的只是virtual AbsMatrice::print() = 0;

首先,由于AbsMatrice是纯虚拟的,因此不能按值返回抽象类型,因此必须返回引用或指针:

AbsMatrice<M, N, T>& mul(AbsMatrice<M, N, T> &a);
                   ^
AbsMatrice<M, N, T>& add(AbsMatrice<M, N, T> &a);
                   ^

其次,基类的析构函数必须声明为virtual,以避免潜在的内存泄漏。

virtual ~AbsMatrice();