C ++ полиморфизм с шаблоном класса, нет соответствующей функции для вызова - PullRequest
1 голос
/ 17 июня 2019

Я пишу шаблон класса, который может принимать одно из следующих значений: int8_t, int16_t, int32_t, float и double. Вот оно:

#ifndef OPERAND_HPP
# define OPERAND_HPP

# include "IOperand.hpp"
# include <regex>

template <typename T>
class Operand : public IOperand {
private:
    /* Constructors - Destructors */
                            Operand() = default;

    /* Attributes */
    T                       _num;
    eOperandType const      _type;
    std::string const       &_value;

    /* Static functions */
    static int8_t           getValue(Operand<int8_t> const *it) { return it->getNum(); }
    static int16_t          getValue(Operand<int16_t> const *it) { return it->getNum(); }
    static int32_t          getValue(Operand<int32_t> const *it) { return it->getNum(); }
    static float            getValue(Operand<float> const *it) { return it->getNum(); }
    static double           getValue(Operand<double> const *it) { return it->getNum(); }

public:
    /* Constructors - Destructors */
    explicit                Operand(eOperandType t, std::string const &v, T n) : _num(n), _type(t), _value(v) {}
                            Operand(Operand const &rhs) : Operand(rhs.getType(), rhs.toString(), rhs.getNum()) {};
                            ~Operand() override = default;

    /* Operator overloads */
    Operand<T>              &operator=(Operand const &rhs) {
        _num = rhs.getNum();
        _type = rhs.getType();
        _value = rhs.toString();
        return *this;
    }

    IOperand const          *operator+(IOperand const &rhs) const final {

        Operand::getValue(&rhs);

        return &rhs;
    }

    IOperand const          *operator-(IOperand const &rhs) const final { return &rhs; }
    IOperand const          *operator*(IOperand const &rhs) const final { return &rhs; }
    IOperand const          *operator/(IOperand const &rhs) const final { return &rhs; }
    IOperand const          *operator%(IOperand const &rhs) const final { return &rhs; }

    /* ------------------------------------------------- Exceptions ------------------------------------------------- */
    class DivisionByZero : public std::exception {
    public:
        char const          *what() const noexcept final { return "division by zero"; }
    };

    class ModuloByZero : public std::exception {
    public:
        char const          *what() const noexcept final { return "modulo by zero"; }
    };

    class Overflow : public std::exception {
    public:
        char const          *what() const noexcept final { return "overflow"; }
    };

    class Underflow : public std::exception {
    public:
        char const          *what() const noexcept final { return "underflow"; }
    };
    /* -------------------------------------------------------------------------------------------------------------- */

    /* Member functions */
    T                       getNum() const { return _num; }
    int                     getPrecision() const final { return static_cast<int>(_type); }
    eOperandType            getType() const final { return _type; }
    std::string const       &toString() const final { return _value; }
};

#endif /* OPERAND_HPP */

Этот класс наследуется от следующего интерфейса:

#ifndef IOPERAND_HPP
# define IOPERAND_HPP

# include <string>

enum eOperandType {
    INT8,
    INT16,
    INT32,
    FLOAT,
    DOUBLE
};

class IOperand {
public:
    /* Constructors - Destructors */
    virtual                     ~IOperand() = default;

    /* Operator overloads */
    virtual IOperand const      *operator+(IOperand const &) const = 0;
    virtual IOperand const      *operator-(IOperand const &) const = 0;
    virtual IOperand const      *operator*(IOperand const &) const = 0;
    virtual IOperand const      *operator/(IOperand const &) const = 0;
    virtual IOperand const      *operator%(IOperand const &) const = 0;

    /* Member functions */
    virtual int                 getPrecision() const = 0;
    virtual eOperandType        getType() const = 0;
    virtual std::string const   &toString() const = 0;
};

#endif /* IOPERAND_HPP */

Я пытаюсь реализовать перегрузку оператора +. Эта функция имеет два аргумента IOperand & as, но мне нужно получить доступ к атрибуту _num указанных аргументов. Получатель этого атрибута находится не в базовом классе, а только в производном классе. Я пробовал полиморфизм со следующими функциями:

    static int8_t           getValue(Operand<int8_t> const *it) { return it->getNum(); }
    static int16_t          getValue(Operand<int16_t> const *it) { return it->getNum(); }
    static int32_t          getValue(Operand<int32_t> const *it) { return it->getNum(); }
    static float            getValue(Operand<float> const *it) { return it->getNum(); }
    static double           getValue(Operand<double> const *it) { return it->getNum(); }

но я получаю следующее сообщение об ошибке при компиляции clang ++:

./Operand.tpp:41:15: error: no matching function for call to 'getValue'
        (void)Operand::getValue(&rhs);
./Operand.tpp:19:29: note: candidate function not viable: cannot convert from base class pointer 'const IOperand *' to derived class pointer 'const Operand<int8_t> *'
      (aka 'const Operand<signed char> *') for 1st argument
    static int8_t           getValue(Operand<int8_t> const *it) { return it->getNum(); }

Сообщение об ошибке довольно многословно, и я понимаю, в чем проблема. Однако я не уверен, как это исправить, или был бы более элегантный подход к моей проблеме. Я мог бы, вероятно, сойти с рук с помощью динамического приведения или даже использовать 5 различных классов вместо шаблона, но это не кажется таким хорошим.

Может ли кто-нибудь указать мне правильное направление?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...