Можно ли перегрузить оператор, принимающий ссылки / указатели на абстрактный класс в качестве входных данных? - PullRequest
1 голос
/ 18 октября 2019

Я работаю над программой на c ++, которая должна провести дифференцирование по символу данного выражения. Например, производная (5x) будет ((0*x) + (5*1)). Обратите внимание, что целочисленный коэффициент также рассматривается как переменная или функция, следовательно, используется правило произведения. Другой пример: (5 + (8 * x)) будет иметь значение (0 + ((0*x) + (8*1))). Дальнейшего упрощения не требуется.

Задача требует наличия абстрактного базового класса «Выражение» с чисто виртуальными методами, и из него должны происходить производные классы, такие как Number, Variable и т. Д. Цель - прочитать выраженияформу, приведенную выше, и распечатайте их соответствующие символьные производные.

Я добился определенного успеха в решении этой задачи без перегрузки каких-либо операторов. Вот что я имею в виду:



#include <iostream>
#include <string>


class Expression
{
public:
    virtual Expression* diff() = 0; //Derivative Calculator
    virtual void print() = 0;
    virtual std::string stringget() = 0; //Prints current expression
};


//--------------------Number Class--------------------//
class Number : public Expression
{
private:
    int num;
    std::string snum;

public:

    //Constuctors
    Number(int n) : num(n), snum(std::to_string(num)) { }
    Number() : num(0), snum("0") { }

    // Rule of three does not apply as class does not contain pointer variables

    //Differentiation function
    Expression* diff()
    {
        num = 0;
        snum = std::to_string(0);
        return this;
    }

    void print()
    {
        std::cout << num << std::endl;
    }

    std::string stringget()
    {
        return snum;
    }

};


//--------------------Variable Class--------------------//
class Variable : public Expression
{
private:
    std::string var;

public:

    //Constructors
    Variable(std::string v) : var(v) { }
    Variable() : var("x") { }

    //Functions
    Expression* diff() override
    {
        var = "1";
        return this;
    }

    void print() override
    {
        std::cout << var << std::endl;
    }

    std::string stringget() override
    {
        return var;
    }

};



//--------------------Addition/Sum Class--------------------//
class Add : public Expression
{
private:
    std::string sum;
    std::string plus = "+";
    std::string leftpar = "(";
    std::string rightpar = ")";
    Expression* laddend; //left addend storage
    Expression* raddend; //right addend storage


public:
    //Constructors
    Add(Expression* a, Expression* b)
    {
        sum = leftpar + (*a).stringget() + plus + (*b).stringget() + rightpar;
        laddend = a;
        raddend = b;
    }
    Add(Expression& a, Expression& b)
    {
        sum = leftpar + (a).stringget() + plus + (b).stringget() + rightpar;
        laddend = &a;
        raddend = &b;
    }

    //Copy Constructor
    Add(const Add& src) : sum(src.sum), plus(src.plus), leftpar(src.leftpar), rightpar(src.rightpar), laddend(src.laddend), raddend(src.raddend) { }

    //Assignment operator
    Add& operator =( Add& src ) { sum = src.sum; return *this; }

    //Destructor
    ~Add() { delete laddend; delete raddend; laddend = NULL; raddend = NULL;}

    //
    void print() override
    {
        std::cout << sum << std::endl;
    }

    //derivative calculator
    Expression* diff() override
    {
        laddend = (*laddend).diff();
        raddend = (*raddend).diff();
        sum = leftpar + (*laddend).stringget() + plus + (*raddend).stringget() + rightpar;
        return this;
    }

    //Expression getter
    std::string stringget() override
    {
        return sum;
    }

    //Overload
    Expression& operator +( Expression* rhs)
    {
        Add* res = new Add(this, rhs);
        return *res;                        
    }
};


//--------------------Product/Multiplication Class--------------------//
class Mul : public Expression
{
private:
    std::string product = "(";
    std::string ast = "*";
    std::string plus = "+";
    std::string leftpar = "(";
    std::string rightpar = ")";
    Expression* multiplicand; //left argument storage
    Expression* multiplier; //right argument storage

public:
    //Constructors
    Mul(Expression* a, Expression* b)
    {
        product = product + (*a).stringget() + ast + (*b).stringget() + rightpar;
        multiplicand = a;
        multiplier = b;
    }

    void print() override
    {
        std::cout << product << std::endl;
    }

    Expression* diff() override
    {
        std::string lvar = (*multiplicand).stringget(); //before differentiation
        std::string rvar = (*multiplier).stringget();   //before differentiation

        multiplicand = (*multiplicand).diff();
        multiplier = (*multiplier).diff();
        product = leftpar + leftpar + (*multiplicand).stringget() + ast + rvar + rightpar + plus + leftpar + lvar + ast + (*multiplier).stringget() + rightpar + rightpar;
        return this;
    }

    std::string stringget() override
    {
        return product;
    }


    //Overload
    Expression& operator *( Expression* rhs)
    {
        Mul* res = new Mul(this, rhs);
        return *res;                        
    }
};



int main()
{
    Expression* test = new Mul(new Number(6), new Variable("x"));

    std::cout << "Current Expression: " << test->stringget() << std::endl;

    Expression* test2 = test->diff();

    std::cout << "Differentiated Expression: " << test2->stringget() << std::endl;
    Add x(test, test2);
    //  x = test + test2 * test;
delete test;



    return 0;
}

, который успешно компилируется со следующим выводом:

Current Expression: (6*x)
Differentiated Expression: ((0*x)+(6*1))

Теперь выражение (6*x) было создано с помощью строки Expression* test = new Mul(new Number(6), new Variable("x")); Нотак как моя цель - прочитать выражения вида (6*x) и даже более сложные выражения, например (((4*x)+(x*x))-x), а затем интерпретировать их и, наконец, дифференцировать, единственный способ - перегрузить операторы. Здесь я получаю проблемы.

Проблемы

Как вы могли заметить в коде, я перегружен операторами сложения и умножения. Однако, когда я пытаюсь запустить такой код, как

x = test + test2 * test1;

(эта строка закомментирована в приведенном выше коде), я получаю сообщение об ошибке. Более того, даже с одним оператором, например,

test = test + test2;

я получаю ошибку

error: invalid operands of types 'Expression*' and 'Expression*' to binary 'operator+'|

или

error: invalid operands of types 'Expression*' and 'Expression*' to binary 'operator+'|

Для меня это не имеет смысла, поскольку типы параметров совпадают.

Что еще я пробовал?

IЯ пытался передать параметры по ссылке, а также по ссылке, но результат тот же. Я также попытался написать описание перегрузки оператора как функцию, не являющуюся членом, но это выдает ошибку

must have an argument of class or enumerated type

Я также попытался изменить типы возвращаемых значений с Expression& на Expression* и сделать необходимые последующиередактирует но ошибки одинаковы. Я даже пытался реализовать правило троек для всех классов - хотя это и не обязательно - но результат тот же.

Буду признателен за любую помощь в том, что мне не хватает.

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