一个简单的计算器类

作者在 2011-04-17 16:46:15 发布以下内容
#include<iostream>
#include<string>
using namespace std;
class Computer
{
    double result;//保存运算结果
    int    index; //保存expr的下标,index只会增大或者不变,不可能减少
    string expr;  //保存表达示
    int    paren; /*'(' paren加1,')'paren减1。一旦paren为负时就肯定是输入有错,运算全部结束后其值不为零也是出错。可以增加一个小类来做为paren的类型*/
protected:
    char 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),index(0),paren(0)
{
    result = comput(getLeftV(true));
}
//每遇到一个左括号都会当成一个新的表达示来调用comput(double),所以在comput(double)里不用考虑括号的情况
double Computer::comput(double lv)
{
    while(index < expr.size())//控制运行
    {
        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;
    char ch;
    while(isdigit(ch = expr[index]))/*这里不使用atoi(const char*)是考虑到通过r 的长度来获取消耗字符的数量不一定准确*/
    {
        index++;
        r *= 10;
        r += ch-'0';
    }
    if(ch == '.')
    {
        int i = index;
        double r2 = 0;
        while(isdigit(ch = expr[i]))
        {
            r2 *= 10;
            r2 += ch-'0';
            ++i;
        }
        if(i-index >1)//防止r2除0
        {
            r += r2/(10*(i-index-1));    
        }
        index = i;//更新
    }
    return r;
}
double Computer::getLeftV(bool t)
{//判断下index的值是否合法,代码会更健壮
    char c = expr[index];
    if(c == '-')//处理负数和取反的代码
    {
        ++index;
        return -getLeftV(true);//通过传递参数true让getLeftV()尽可能快的返回它获取的值
    }
    if(c == '(')
    {
        ++index;
        paren++;//括号的处理
        return comput(getLeftV(true));//调用comput()是把括号里的表达看成一个新的表达示。
    }
    if(isdigit(c))
    {
        double lv = getDouble();
        char sign = expr[index];//获取操作数后面紧跟着的运算符号
        if(t || sign==')' || sign=='-' || sign=='+')//t就是传递进来的bool参数
        {
            
            if(sign==')'){
                --paren;//维护paren的值
                ++index;//跳过右括号
            }
            return lv;
        }
        else
        {
            return comput(lv);//否则就把获取的值当成新的表达示的第一个操作数。
        }
        
    }
//进入这里的都是出错的情况
}
double Computer::getRightV(bool t)//参看getLeftV(bool)
{
    return getLeftV(t);
}
int main()
{
    string str;
    cin >> str;
    cout << Computer(str) <<endl;
    return 0;
}
默认分类 | 阅读 1492 次
文章评论,共0条
游客请输入验证码
浏览30053次