前言
2020/9/17 更新: 现已有采用std::list管理的多项式程序,请参见 github.com/tsagaanbar/fraction-class-cpp
这周,我们面向对象程序设计的老师没有讲新课,而是给我们布置了一个PBL任务,发下来一个编译好的exe可执行文件,然后让学生们两两组队写出源代码。
什么是PBL?即问题驱动教学法(Problem-Based Learning, PBL),详情请自行查询。
至于为什么发一个exe文件下来,老师本人的解释是“不知道如何描述出这个作业的要求”,索性便直接发给我们编译出来的程序,免去文字表述的苦恼与不便之处。
晴*:或者我的要求是:输入三个多项式,并实现多项式加,减,乘和求导运算
晴*:我的意思,我这样留的话,作业太笼统,你根本不知道做什么
不知道大家还记得中学时期的一个物理实验,就是用万用表探索黑盒,是不是感到非常的相似呢?
就我个人的感觉,其实这个作业还是有不小难度的,可以赶上C语言程序设计的大作业了。(有趣的是,昨天还有同学和我说,觉得这几周的C++作业太没意思了,而如果做大作业就能学到很多东西,所以我想这下他一定会非常高兴了!)
目录
正文
程序要求
那么接下来让我们进入正题吧。项目要求大概就是这样:
定义并实现多项式类(polynomial),实现多项式加,减,乘及求导运算,并用一个交互式主程序测试、使用该多项式类。
需要指明的是,这里的多项式指的是“一元非负正整数次数多项式”(以下简称“多项式”);比如像4x^3 + 5x^2 + 2.5x + 1
这种。
要求的交互式主菜单如下:
---------------The Commands---------------
s - 设置当前多项式
l - 调用assign_coef函数
t - 调用add_to_coef函数
c - 调用clear函数
v - 显示当前多项式
a - 显示所有多项式
d - 对当前多项式求导并显示
e - 计算当前多项式的值
+ - 显示A+B的和
- - 显示A-B的差
* - 显示A*B的积
q - quit
------------------------------------------
在老师写的程序里,可以存储a、b、c三个多项式;下面是对一些也许不能“顾名思义”的功能的解释:
s
:选择要操作的多项式;l
:调用assign_coef
函数,指定某一次数的项的系数t
:调用add_to_coef
函数,给某一次数的项的系数加上指定的系数c
:将当前多项式归零e
:调用后输入一个值,输出将该值代入多项式后得到的结果
初探黑盒与思路形成
这里感谢班上何同学,经过他对“黑盒”的“试探”,我们知道了这些信息:
- 所有指数输入范围为0<=x<=30(int x,只能输入数值);
- 所有系数输入范围为double(只能输入数值);
提醒:以下内容仅供参考,并且可能会影响到读者自己的程序设计思路,建议有了成熟的思考后再继续进行阅读和讨论:
我先来说一下自己第一眼看到这个任务的想法,我想,多项式是由单项式组成,那么可以先写好单项式的类,然后再写多项式的类,并用动态内存分配来实现存储。这样的话,可以保留下多项式原本的模样(指每一项的顺序),而且更有该课程的风格——即我只要先写好单项式的输出、单项式之间的运算方法,然后再写多项式的类的时候,可以直接调用单项式的函数,相当于一种化繁为简的操作。但这只是想法,并没有实践,所以不清楚可行性,有机会的话会进行尝试。
(大概是因为做作业前看了一点《新标准C++程序设计教程》上关于运算符重载的内容,书上用一个自定义的String类作为例子来进行讲解;而我个人感觉,多项式和书上的String之间似乎是有一点相似性的,于是才有了这样的想法)
不过,既然老师的“黑盒”都给出来了,我想首先还是尽量先按照老师的思路来实现吧。经过自己的一些调试,发现老师的多项式输出格式皆为从高次到低次降幂排列,而且有自动“合并同类项”的功能(就是执行add_to_coef()
、assign_coef()
过后,系数会自动更改,而不是缀在末尾或者其他什么地方)。我在学习群里分享了这个发现,何同学猜测是通过链表实现的;可是我个人没见过什么高级方法,觉得老师应该使用一个数组实现的,存储对应次数项的系数。我之所以这样猜测,是因为这样实现起来比较简单,并不用费心去把每一项按次数排序,而且进行系数的累加也很方便。并且结合老师程序的bug,这样很说得过去。然而这样的缺点也显而易见,因为数组总有一个大小上限,指数过大会出错,需要留心设置一些语句来进行判断,防止溢出。
八哥啄柿子 —— 拣软的欺
那我们就开始吧,从最简单的做起。
写这种比较大的作业,我一般喜欢从最简单的事情做起。不如就从写这个类开始吧,我们先来想一下怎么声明,比如起什么名字,用什么数据存储,需要有哪些函数,这些函数操作什么,返回什么,接受什么参数。
类的名字就叫Polynomial
吧。
存储数据的方式
第一,我们要来存储这个多项式。按照前文所说,我们用一个数组来存储每一项的系数。我英语不大好,用词典查了一下,系数的英语是“coefficient”,指数是“exponent”。那么,我们的数组就叫做coefs[]
吧!它应该是double
型,有30个数据,第i个位置用来存储i次项的系数。
double Polynomial::coefs[30];
类的功能函数的思路
注意这里既然选择了使用数组的思路,那么接下来的思考都要围绕它展开了。先来想一下,要改变多项式的某一项该怎么操作呢?
指派某一项的系数,比如把x的5次项的系数设为2:coefs[5] = 2;
累加某一项的系数,比如把x的3次项的系数加上1:coefs[3] += 1;
减去某一项的系数,比如把常数项减去3:coefs[0] -= 3;
然后开始写add_to_coef()
、assign_coef()
这两个函数吧;这里停一下想想,要不要把输入功能写到这个函数里面呢?我觉得还是应该把这两个成员函数写得单纯一点,做的事情简单一点,尽可能直接。这两个函数可能会在很多地方被调用,比如add_to_coef()
函数,不仅可以单独调用它,或许还可以在进行多项式的乘法的时候调用它。函数应该接受两个参数,一个是要操作的项的系数,一个是系数的值;我们把形参设为(double) coef
和(int) expo
。
void Polynomial::assign_coef(double coef, int expo);
void Polynomial::add_to_coef(double coef, int expo);
接下来还要有加、减、乘的函数。这里有些读者可能会只想着完成老师的任务——完成内存中多项式“A”、“B”的加减乘——然后把这个过程写成所谓的成员函数,结果在过程中遇到许多问题。事实上并不该这么做,这个Polynomial
类(或者说任何一个类),应该把它想成一个机体:成员函数用来接收外部信息并进行一些可能的处理,然后对自身的成员变量进行改动,或者对外进行一些输出、反馈;成员变量用来保存类的属性、数据之类的。一定要把它和它的用过程区分开来;我个人认为可以把类想成一种智能的数据类型,而不是把程序过程生搬硬套进来。
(就我接触到的情况,身边有同学似乎还没有适应这种模式。当然我毕竟也是初学,不能说我这种理解就是对的,如果有误欢迎指正。)
举个例子,我们写add()
、substract()
、multiply()
三个函数,执行加减乘的操作;函数接受一个参数,是Polynomial&
类型,即对Polynomial
类的引用。比如下面这样的语句:
Polynomial a,b;
/* ... */ //对多项式进行赋值操作
a.multiply(b); //将a乘上b
a.print(); //输出多项式a
cout << endl;
执行a.multiply(b);
语句,代表着将多项式a
乘上多项式b
,比如a
存储的多项式是x+1
,b
存储的多项式是x+2
,则执行该语句后,a
存储的多项式变成了x^2+3x+2
。
那么老师要求显示“A + B”的结果该怎么办呢?只要显示,而不更改原有的数据,下面是一种方式。
Polynomial tmp; //生成一个临时的多项式tmp
tmp.set_to(a); //用多项式a给tmp赋值
tmp.multiply(b); //理解起来就是 tmp = tmp * b = a * b
tmp.print(); //输出tmp,也就是a*b的结果
cout << endl;
加、减、乘三个函数,还有求导、求值功能的声明:
void Polynomial::add(Polynomial&); //为当前多项式加上一个多项式
void Polynomial::substract(Polynomial&); //从当前多项式中减去一个多项式
int Polynomial::multiply(Polynomial&); //将当前多项式乘上一个多项式
void Polynomial::derivate(); //对当前多项式求导
long double Polynomial::value(double); //代值进多项式进行运算
我计划将加、减、乘、求导这些函数都写成修改自身的函数,而不是返回一个Polynomial
类,或者在控制台上输出结果。multiply()
函数设置返回值是因为该函数可能会很容易遇到运算时指数超出限定的情况,这种情况下会返回一个0
,表示操作不成功。value()
设成long double
型,是出于表达式的值可能会很大的考虑。
根据老师的要求,还要写clear()
函数,用来清空多项式;我觉得还需要一个set_to()
函数,用来将另一个多项式赋值过来。
至此,函数的声明完成了一大半,可以想成一个人能够完成喝水、行走等动作了。接下来,我们还需要让类能够输出自己,毕竟存储在coefs[]
数组里面的数据不直观,单纯看就是一堆有序的数字序列,这个过程就好比一个人用语言表达出自己的思想。 对于我们的Polynomial
类,这个“表达”的过程,就写一个print()
函数来执行吧。
为了完善这个类,还要写构造函数,用来初始化空间;必要的话还要写析构函数。
为了给自己挑战,我决定把课堂上一个同学讲的“从字符串设定多项式”的功能写出来,叫做str_set()
;还有一个output_term()
用来输出某个单项式,这个后面解释。
类的声明
那么我们的类的声明就这样了:
class Polynomial //仅支持一元多项式,且无分数、负数指数幂
{
private:
double coefs[30];
public:
void assign_coef(double, int);
void add_to_coef(double, int);
void add(Polynomial&);
void substract(Polynomial&);
int multiply(Polynomial&);
void derivate();
long double value(double);
void set_to(const Polynomial&);
void str_set(char*);
void print();
void clear();
void output_term(int );
void output_term(double , int );
Polynomial(); //无参的构造函数,初始化为零
Polynomial(double*); //从一个数组初始化
//复制构造函数可以就用默认的吧,所以就不写了
};
类的代码实现
接下来是疯狂写代码、调代码;事先说明,经过实践检验,本人的代码能力不高,很多时候看了别人的代码才恍然大悟,所以接下来的放代码环节仅供参考。
输出一个单项式
这个函数和它的重载下面就会用到,就是根据给定系数和次数输出一个x的单项式。其实print()
也能调用这个来分解代码压力,但我一开始没想到……
void Polynomial::output_term(int expo)
{
if (coefs[expo] == 0) return;
if (coefs[expo] < 0) cout << " - ";
if (coefs[expo] != 1 && coefs[expo] != -1) cout << abs(coefs[expo]);
if (expo == 1) cout << "x";
else if (expo > 1) cout << "x^" << expo;
}
void Polynomial::output_term(double coef, int expo)
{
if (coef == 0) return;
if (coef < 0) cout << " - ";
if (coef != 1 && coef != -1) cout << abs(coef);
if (expo == 1) cout << "x";
else if (expo > 1) cout << "x^" << expo;
}
给指定次数的项指定系数、叠加系数
void Polynomial::assign_coef(double coef, int expo) //重新指定系数
{
coefs[expo] = coef;
}
void Polynomial::add_to_coef(double coef, int expo) //给某一项系数加上一定的值
{
coefs[expo] += coef;
}
实现功能这样就可以了,但是我想让函数更智能(人性化)一点,就是调用它时,如果无法成功赋值就输出一些提示的话语,比如“某某项未成功加上”这种,于是:
void Polynomial::assign_coef(double coef, int expo) //重新指定系数
{
if (expo < 0) {
cout << "# The exponent needs to be a natural number!\n";
cout << "# Failed to assign one term as: '";
output_term(coef, expo);
cout << "'. \n";
return;
}
if (expo > 29) {
cout << "# The exponent is too big!\n";
cout << "# Failed to assign one term as: '";
output_term(coef, expo);
cout << "'. \n";
return;
}
coefs[expo] = coef;
}
void Polynomial::add_to_coef(double coef, int expo) //给某一项系数加上一定的值
{
if (expo < 0) {
cout << "# The exponent needs to be a natural number!\n";
cout << "# Failed to add term: '";
output_term(coef, expo);
cout << "'. \n";
return;
}
if (expo > 29) {
cout << "# The exponent is too big!\n";
cout << "# Failed to add term: '";
output_term(coef, expo);
cout << "'. \n";
return;
}
coefs[expo] += coef;
}
这样,假如某一项不能成功修改,就会在输出错误信息的同时把这一项输出到屏幕上。
多项式的加减
加减很好办,只需要对应位置相加 / 相减就好了。
void Polynomial::add(Polynomial& n)
{
for (int i = 0; i < 30; i++)
{
//add_to_coef(n.coefs[i], i);
coefs[i] += n.coefs[i];
}
}
void Polynomial::substract(Polynomial& n)
{
for (int i = 0; i < 30; i++)
{
//add_to_coef(-n.coefs[i], i);
coefs[i] -= n.coefs[i];
}
}
多项式的乘法
我们回忆一下自己做多项式乘法的方法,大概来讲就是“挨个乘”,也就是把多项式相乘看成若干个单项式相乘;而单项式相乘就是系数相乘、指数相加。因为计算过程中可能会出现多个同类项,为了便于累加(合并)它们,我们新建一个临时的Polynomial
类,用来把单项式相乘的结果们存放进去,最后再用这个临时的类去更新我们原有的类。
int Polynomial::multiply(Polynomial& n)
{
Polynomial temp;
for (int i = 0; i < 30; i++)
{
if (coefs[i] == 0) continue; //某项系数为0,则跳过
for (int j = 0; j < 30; j++)
{
if (n.coefs[j] == 0) continue; //某项系数为0,则跳过
if (i + j > 29) //单项式相乘的结果的指数过大
{
cout << "# Excessive exponent encountered! \n";
cout << "# Try a polynomial with smaller exponents. \n";
return 0;
}
temp.add_to_coef(coefs[i] * n.coefs[j], i + j);
}
}
set_to(temp);
return 1;
}
需要注意的是,在乘法过程中,很可能会出现指数超出范围的情况,所以需要设置一个判断,如果出错,则返回值0
,并输出一些信息(输出信息的过程可以设置在函数里,也可以设置在调用处)。
求导、求值
很简单,就不多说了
void Polynomial::derivate()
{
for (int i = 1; i < 30; i++)
{
coefs[i - 1] = coefs[i] * i;
}
}
long double Polynomial::value(double x)
{
long double value = 0;
for (int i = 0; i < 30; i++)
{
value += coefs[i] * pow(x, i);
}
return value;
}
输出这个多项式
我们这个多项式在内存中存储的样子,只是一串有序的数字,是很不直观的,需要写一个函数来把它直观的显示出来。比如这样:
cout << coef << "x^" << expo;
或者用C的格式输入输出:
printf(" %fx^%d ", coef, expo);
但是这样,对于我们的项x
或者5
,就可能会输出如1x^1
、5x^0
这样的表达式,甚至会有0x^5
这种没有意义的输出;这不太符合我们的的阅读习惯,因此需要输出过程加上条件来判断。总结一下,大概有这些特例需要考虑:
- 系数为0的项不输出;
- 首项为正不用输出
+
,但是其他的项为正需要额外输出+
; - 1次项应省略指数幂,即
1x^1
应输出为x
; - 0次项为常数项,不输出
x
相关的东西。
然后就遍历整个coefs[]
数组,逐项输出,遇到系数为0的项就跳过。代码实现:
void Polynomial::print1()
{
bool flag = false; //记录是否至少输出了一项
for (int i = 29; i >= 0; i--)
{
if (coefs[i] == 0) continue;
bool if_negative = false;
if (coefs[i] < 0) if_negative = true;
if (if_negative) cout << " - ";
else if (flag) cout << " + ";
flag = true;
if (i == 0 || abs(coefs[i]) != 1) cout << abs(coefs[i]);
if (i > 1) cout << "x^" << i;
else if (i == 1) cout << "x";
}
//cout << endl;
}
其实自己一开始写的print()
函数比这个繁琐,是分了第一项、中间项和常数项进行的。放在下边,有兴趣的读者可以看一下。
void Polynomial::print()
{
int i = 29;
bool flag = 0; //记录是否至少输出了一项
while (coefs[i] == 0 && i > 0) i--; //跳过高次零系数项
if (i != 0) //单独输出最高次项
{
if (coefs[i] < 0) cout << " - ";
if (coefs[i] != 1 && coefs[i] != -1) cout << abs(coefs[i]);
if (i == 1) cout << "x";
else cout << "x^" << i;
flag = 1;
i--;
}
for (; i > 0; i--)
{
if (coefs[i] == 0) continue;
flag = 1;
if (coefs[i] > 0) cout << " + ";
else cout << " - ";
if (coefs[i] != 1 && coefs[i] != -1) cout << abs(coefs[i]);
if (i == 1) cout << "x";
else cout << "x^" << i;
}
//输出常数项
if (coefs[0] == 0) return;
if (flag == 1 && coefs[0] > 0) cout << " + ";
if (coefs[0] < 0) cout << " - ";
cout << abs(coefs[0]);
}
从另一个多项式赋值、归零操作及构造函数
void Polynomial::set_to(const Polynomial& n)
{
for (int i = 0; i < 30; i++) coefs[i] = n.coefs[i];
}
void Polynomial::clear()
{
for (int i = 0; i < 30; i++) coefs[i] = 0;
}
Polynomial::Polynomial()
{
clear();
}
Polynomial::Polynomial(double* n_coefs)
{
for (int i = 0; i < 30; i++) coefs[i] = n_coefs[i];
}
从字符串设置多项式
假如一个多项式有很多项,或者你的朋友给你发来一个自己的多项式,就目前的函数来讲,只能一次次调用add_to_coef()
或者assign_coef()
来进行设置,这样很麻烦,而且容易出错。
为了方便使用,我决定加入这个从字符串设置多项式的功能。但具体怎么处理输入进来的字符串呢?这个功能其实我自己想了不少时间,因为晚上思路不清晰,加之没有仔细分析情况,到第二天早上起来花了一些时间才最终写成。
那我们就来具体看一下,一个多项式由若干单项式组成,而一个单项式的情况又有很多种,比如可能有x
、x^2
、3x^5
、-2.3x^8
这么多种情况。怎样才能把它们都识别出来呢?
首先是“切片”,或者说要让程序会断句,知道怎样才是一个单项式。这里我们不讨论乘除运算的情况,假设输入的表达式仅由+
或-
连接。很显然,+
或-
就是将这些单项式分割开的符号。
分析单项式可能的情况:
- 首先可能会遇到
'+'
或'-'
(首项的话可能直接遇到系数); - 接下来可能会遇到系数,也可能直接遇到
'x'
,也就意味着系数是1
; - 系数后面,可能是
'x'
(一次项),也可能直接是'+'
、'-'
或'\0'
(即该项已结束,为常数项); - 然后可能会遇到
'^'
,也就意味着接下来的是指数; - 最后就是
'+'
、'-'
或'\0'
,意味着该项已结束。
自己写出来的代码:
void Polynomial::str_set(char* p)
{
//字符数组传入前已经经过修剪,不然需要一个循环语句略去行首空格
while (*p != '\0') //遍历存放输入的字符数组
{
bool if_negative; //记录当前项是否为负
if (*p == '-') //仅当第一个字符是'-',才说明该项为负
{
if_negative = true;
p++; //指针指向下一格
}
else if_negative = false; //除此之外,都说明为正项
if (*p == '+') p++; //如果当前指针读到了'+',也需要把指针挪到下一个位置
//否则接下来的while语句不能正常执行其忽略空格的功能
while (*p == ' ')p++; //略去从运算符后面可能存在的空格
double t_coef = 0;
bool if_x = false; //该项是否含x
if (*p == 'x') //如果遇到的字符就是x,说明当前项系数为1
{
t_coef = 1;
if_x = true;
}
else t_coef = atof(p); //不然,就当是存在系数,获取到这个系数
if (if_negative) t_coef = -t_coef; //如果该项为负,则应当把系数改为相反数
//接下来定位到下一个符号:
//如果定位到'+'、'-'或'\0',说明这项已经结束
//如果定位到符号是'^',说明这一项应该有指数
while (*p != '\0' && (*p != '^' && *p != '+' && *p != '-'))
{
if (*p == 'x') if_x = true; //遇到x要记录下来
p++;
}
int t_expo = 0;
if (*p == '^')
{
p++;
t_expo = atoi(p); //获取指数
add_to_coef(t_coef, t_expo); //写入
while (*p != '\0' && *p != '+' && *p != '-') p++;
//记得把指针挪到下一项开始,便于处理
}
else if (*p == '+' || *p == '-' || *p == '\0') //说明这一项已经没有了
{
if (if_x) t_expo = 1;
else t_expo = 0;
add_to_coef(t_coef, t_expo);
}
}
}
目前的这段代码要求输入符合规范,出现非法符号可能会影响读取。
交互式界面
一些其他的函数
修剪字符串
void trim(char* strIn, char* strOut) // support in-place opreation
{
char* a = strIn, * b;
while (*a == ' ' || *a == '\n' || *a == '\t') a++; // ignore spaces at the beginning
b = strIn + strlen(strIn) - 1; // get pointer pointing at the end of the line
while (*b == ' ' || *b == '\n' || *a == '\t') b--; // ignore spaces at the end
while (a <= b) *strOut++ = *a++; // transplace
*strOut = '\0';
}
读入一整行输入
int Getline(char* dstStr)
{
char c;
int k = 0;
scanf("%c", &c);
while (c != '\n')
{
*dstStr++ = c;
k++;
scanf("%c", &c);
}
*dstStr = '\0';
return k;
}
应对非法输入
有时候,在用cin
读入int
型数据时,如果输入了一个2.5
,则该int
读入2
,留下来.5
存在缓冲区;假如接下来读入的是double
型,则直接得到0.5
。还有就是输入非法可能会带来一些问题。我个人目前的处理方式如下:
Getline(usr_input);
trim(usr_input, usr_input);
//double result = atof(usr_input);
关于cin
的使用事项,可以参阅其他教程。
命令提示界面
void command_promption()
{
cout << "---------------The Commands--------------- \n";
cout << "s - 设置当前操作的多项式(A或B) \n";
cout << "l - 调用assign_coef函数 \n";
cout << "t - 调用add_to_coef函数 \n";
cout << "i - 直接输入多项式,每项格式如 -2.3x^3 \n";
cout << "c - 调用clear函数 \n";
cout << "v - 显示当前多项式 \n";
cout << "a - 显示所有多项式 \n";
cout << "d - 对当前多项式求导并显示 \n";
cout << "e - 计算当前多项式的值 \n";
cout << "+ - 显示A+B的和 \n";
cout << "- - 显示A-B的差 \n";
cout << "* - 显示A*B的积 \n";
cout << "h - help \n";
cout << "q - quit \n";
cout << "------------------------------------------ \n";
}
全局变量
把A、B两个多项式设置成全局变量,并且设置一个指针,指向当前操作的多项式。
Polynomial poly_a, poly_b;
Polynomial* now_opreate = &poly_a;
char now_opr = 'A';
根据用户输入,进行操作
主要用一个switch
语句,实现选择。实际写出来发现很长。其实把每个子功能做成单独的函数也不错。
void guide(char choice)
{
char usr_input[100];
//貌似不能在case里面声明变量,于是就放在switch外面了
double t_coef = 0;
int t_expo = 0;
double x;
Polynomial tmp(poly_a);
//需要设置一个临时的类,以免对原本的多项式造成更改
bool m_flag;
switch (choice)
{
case 's':
cout << "Choose which poly. to operate on (A/B) > ";
Getline(usr_input);
trim(usr_input, usr_input);
if (usr_input[0] == 'A' || usr_input[0] == 'a')
{
now_opreate = &poly_a;
cout << "Polynomial A is now chosen!\n";
now_opr = 'A';
}
else if (usr_input[0] == 'B' || usr_input[0] == 'b')
{
now_opreate = &poly_b;
cout << "Polynomial B is now chosen!\n";
now_opr = 'B';
}
else cout << "Polynomial under opreation is " << now_opr << ".\n";
break;
case 'l':
cout << "Input the coef. > ";
Getline(usr_input);
trim(usr_input, usr_input);
t_coef = atof(usr_input);
cout << "Input the expo. > ";
Getline(usr_input);
trim(usr_input, usr_input);
t_expo = atoi(usr_input);
now_opreate->assign_coef(t_coef, t_expo);
cout << "Poly now becomes: ";
now_opreate->print();
cout << endl;
break;
case 't':
cout << "Input the coef. > ";
Getline(usr_input);
trim(usr_input, usr_input);
t_coef = atof(usr_input);
cout << "Input the expo. > ";
Getline(usr_input);
trim(usr_input, usr_input);
t_expo = atoi(usr_input);
now_opreate->add_to_coef(t_coef, t_expo);
cout << "Poly now becomes: ";
now_opreate->print();
cout << endl;
break;
case 'i':
cout << "> ";
Getline(usr_input);
trim(usr_input, usr_input);
now_opreate->clear();
now_opreate->str_set(usr_input);
now_opreate->print();
//now_opreate->print1();
cout << endl;
break;
case 'c':
now_opreate->clear();
cout << "Poly_" << now_opr << " has been cleared!" << endl;
break;
case 'v':
now_opreate->print();
cout << endl;
break;
case 'a':
cout << "Poly_A: "; poly_a.print(); cout << endl;
cout << "Poly_B: "; poly_b.print(); cout << endl;
break;
case 'e':
cout << "Enter the value of x: > ";
Getline(usr_input);
trim(usr_input, usr_input);
x = atof(usr_input);
cout << "Value: " << now_opreate->value(x) << endl;
break;
case 'd':
if (now_opr == 'A') {
tmp.set_to(poly_a);
}
if (now_opr == 'B') {
tmp.set_to(poly_b);
}
tmp.derivate();
tmp.print();
cout << endl;
break;
case '+':
tmp.add(poly_b);
tmp.print();
cout << endl;
break;
case '-':
tmp.substract(poly_b);
tmp.print();
cout << endl;
break;
case '*':
m_flag = tmp.multiply(poly_b);
if (m_flag) tmp.print();
cout << endl;
break;
case 'q':
break;
case 'h': default:
command_promption();
break;
}
return;
}
主函数
用一个while循环来不断获取用户输入,并执行功能:
int main()
{
char choice[100];
choice[0] = 'h';
while (choice[0] != 'q')
{
guide(choice[0]);
cout << "> ";
Getline(choice);
trim(choice, choice);
}
return 0;
}
运行结果
运行结果就不写了吧……
后记
做作业的时候,发现有些自己已经用了很久的功能,都不是了解得很确切,比如atoi()
似乎要求首字符为数字,是最后通过逐语句调试+变量监测才发现的。
还有最开始满屏的红波浪线,以为是编译器出bug了,结果是因为自己class Polynomial
后边加了一个括号……
我认为这个项目还有可以改进的空间,比如可以设置一个静态的成员变量,表示这个多项式类中的未知量的字母:
static char Polynomial::letter;
letter = 'x'
,输出x^5+3x
这种样式;
letter = 'a'
,则输出a^5+3a
这种风格。
还可以重新写过,做成支持分数、负数指数幂的形式,前文有提到过,不再赘述。
就这样,没了。下次见!