计算器类升级版

作者在 2011-04-24 09:03:32 发布以下内容
#include "stdafx.h"

#include<iostream>
#include<string>
#include<sstream>
using namespace std;
class Computer
{
    double result;//保存运算结果
    istringstream expr;  //保存表达示
    int    paren; /*'(' paren加1,')'paren减1。一旦paren为负时就肯定是输入有错,运算全部结束后其值不为零也是出错。可以增加一个小类来做为paren的类型*/
protected:
    int   getSign();//获取运算符号
    double getDouble();//提取一个整数,供下面两个函数调用
    double getLeftV(bool);//bool这个参数的作用是用来说明获取的操作数能不能马上返回
    double getRightV(bool);
    double comput(double lv);//计算的核心函数
public:
    operator double()
    {
        return result;
    }
    Computer(const std::string);
};
Computer::Computer(const std::string str):expr(str),result(0),paren(0)
{
    result = comput(getLeftV(true));
}
int Computer::getSign()
{
    return expr.get();

}
//每遇到一个左括号都会当成一个新的表达示来调用comput(double),所以在comput(double)里不用考虑括号的情况
double Computer::comput(double lv)
{
    int sign = 0;
    while((sign = getSign()) != EOF)//控制运行
    {
        //char sign = expr[index++];//获取运算符号
        switch(sign)
        {
        case '-':
            return comput(lv - getRightV(false));
        case '+':
            return comput(lv + getRightV(false));
        case '*':
            return comput(lv * getRightV(true));//设置成true是因为乘除的优先级高,可以马上获取右操作数
        case '/':
            {
                double rv = getRightV(true);
                if(rv)
                    return comput(lv / rv);
                else
                    ;//出错处理
            }
        default:
            ;
            //错误处理
        }
    }
    return lv;
}
double Computer::getDouble()
{
    double r = 0;
    expr >> r;
    return r;
}
double Computer::getLeftV(bool t)
{
    int c = expr.get();
    double lv = 0;
    if(c == '.' || isdigit(c))
        c = 0;
    const int NUM = 0;
    switch(c)
    {
    case NUM:
        {
            expr.unget();
            lv = getDouble();
            if(t)
                break;
            switch(getSign())
            {
            case EOF:
                break;
            case '+':
            case '-':
                expr.unget();
                break;
            case ')':
                --paren;
                break;
            case '*':
            case '/':
                expr.unget();
                lv = comput(lv);
                break;
            }//switch (sign)
        }//end case NUM
        break;
    case '-':            
        lv = -getLeftV(true);//通过传递参数true让getLeftV()尽可能快的返回它获取的值
        break;

    case '(':
        ++paren;//括号的处理
        lv = comput(getLeftV(true));//调用comput()是把括号里的表达看成一个新的表达示。
        break;

    default:
        ;//error

    }//end switch

    return lv;
}

double Computer::getRightV(bool t)//参看getLeftV(bool)
{
    return getLeftV(t);
}
int main()
{
    string str;
    cin >> str;
    cout << Computer(str) <<endl;
    return 0;
}
在VC2008中编译通过。
使用了标准库中的istringstream类。大大减化了double Computer::getDouble()的代码。
对于异常处理这次也是没写出来。有兴趣的朋友自己添上~
默认分类 | 阅读 1657 次
文章评论,共1条
ytmwxfwxf
2011-10-30 15:32
1
<img src="image/face/4.gif" class="face">&nbsp;&nbsp;路过
游客请输入验证码
浏览31013次