首页 > 解决方案 > 带有纯虚函数的模板类的 C++ 实现

问题描述

我正在开发一个必须能够处理不同类型数据(最终甚至不是数学数据)的计算器,但我被困在Complex数字类的实现中。这是我想要实现的目标:

为什么我要这样创建它?好吧,所有向量空间的唯一共同特征是它们允许两种运算:对相同类型的空间进行求和运算,以及在同一字段中进行点积(或标量积?不确定英文的实际名称)。该字段可能是非常不同的类型(整数双精度字符串等),所以我想用一个模板来制作它。然后每个派生类都会将字段的数据类型指定给模板并实现虚拟操作

这是我此刻的vectorSpace课程代码(完全写在 .h 文件中):

#ifndef VECTORSPACE_H
#define VECTORSPACE_H

template <class T>
class vectorSpace
{
public:
    virtual vectorSpace<T>& sum(const vectorSpace<T>&) const =0;
    virtual vectorSpace<T>& dotProduct(const T&) const =0;
};

#endif // VECTORSPACE_H

在 complex.h 我有这个:

#ifndef COMPLEX_H
#define COMPLEX_H

#include "vectorspace.h"

class Complex : public vectorSpace<double> {
private:
    double re, im;
public:
    Complex(double r=0, double i=0);

    double real() const;
    double imag() const;

    Complex& operator +(const Complex& z) const;
    Complex& sum(const Complex& z) const;
    Complex& operator *(double d) const;
    Complex dotProduct(double d) const;
    //other functions for Complex

};

#endif // COMPLEX_H

最后是我完成的实现:

#include "complex.h"

Complex::Complex(double r, double i) : re(r), im(i) {}

double Complex::real() const{
    return re;
}

double Complex::imag() const{
    return im;
}

Complex& Complex::operator +(const Complex& z) const{
    Complex *aux = new Complex(); //new is not allowed for an abstract class but it should not be abstract anymore
    aux->re = re + z->re;
    aux->im = im + z->im;
    return *aux;
}

Complex& Complex::sum(const Complex &z) const{
    return *this + z;
}

/* I've tried even with this, but it does not work!!
vectorSpace<double>& Complex:sum(const vectorSpace<double>& z) const{
    return *this + z;
}
*/

Complex Complex::operator *(double d) const{
    Complex aux;
    aux.re = re * d;
    aux.im = im * d;
    return aux;
}

Complex& Complex::dotProduct(const double& d) const{
    return *this * d;
}

这只是我所做的最后一次实施尝试。我尝试了各种组合,但我仍然无法让我的Complex班级将其识别为具体而不是抽象。我在哪里做错了?

标签: c++templatespure-virtual

解决方案


问题

您需要vectorSpace在具体派生类中覆盖抽象模板类的以下纯虚拟成员方法Complex

virtual vectorSpace<T>& sum(const vectorSpace<T>&) const = 0;
virtual vectorSpace<T>& dotProduct(const T&) const = 0;

override目前,您提供了两个重载的成员方法,但由于使用了不同的返回类型(即Complex&!= ),这些方法没有被覆盖(在将关键字添加到这两个成员方法后尝试编译vectorSpace<double>&):

Complex& Complex::sum(const Complex &z) const {
    return *this + z;
}

Complex& Complex::dotProduct(const double& d) const {
    return *this * d;
}

一个可能的解决方案

Complex作为附加模板参数传递给基类vectorSpace。使用此附加模板参数的类型更改纯虚拟成员方法的签名。

一种可能的实现[在线试用]:

template< typename T, typename ValueT >
class VectorSpace {

public:

    virtual const ValueT sum(const ValueT&) const noexcept = 0;
    virtual const ValueT dotProduct(T) const noexcept = 0;
};

class Complex : public VectorSpace< double, Complex > {

private:

    double re, im;

public:

    Complex(double r, double i) noexcept 
        : re(r), im(i) {}

    // Do not worry about the const return values; 
    // C++17's Guaranteed Copy Elision will take care of that.

    const Complex operator+(const Complex& z) const noexcept {
        return Complex(re + z.re, im + z.im);
    }

    const Complex operator*(double d) const noexcept {
        return Complex(re * d, im * d);
    }

    const Complex sum(const Complex& z) const noexcept override {
        return *this + z;
    }
    const Complex dotProduct(double d) const noexcept override {
        // Note that this is not a general dot or inner product.
        // This is just scalar multiplication.
        return *this * d;
    }
};

int main() {
    Complex c(1.0, 2.0); // As concrete as can be ;-)
    return 0;
}

我做了一些更改,因为您的堆分配是纯粹的开销和危险的,并且您不能const使用该实例的成员方法将非引用传递给该实例const,除非您真的想滥用 a const_cast)。


推荐阅读