Я работаю над программой на 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*
и сделать необходимые последующиередактирует но ошибки одинаковы. Я даже пытался реализовать правило троек для всех классов - хотя это и не обязательно - но результат тот же.
Буду признателен за любую помощь в том, что мне не хватает.