c++ 基本计算器的灵活可扩展实现附带UI界面

实现一个可灵活扩充功能的计算器, 面向对象设计
可以灵活添加绝大部分运算操作符
并附带ui 界面方便使用

集成库

编译

g++ -fPIC -shared main.cpp -std=c++17  -o cal.so 

计算器可视化

python UI

界面

在这里插入图片描述

功能拓展

比如支持 & bit_and 运算 比如 10 & 5

只需要修改如下

增加新的计算函数

class BitAndOperator : public Operator {
public:
    BitAndOperator() : Operator(2) {}

private:
    OPTYPE cal(OPTYPE *buffer) override {
        return buffer[0] & buffer[1];
    }
};

增加新的优先级

int priority(char op) {
        switch (op) {
            case '(':
                return 100000;
            case '!':
            case '~':
            case 'z':  // z --> 一元+
            case 'y':  // y --> 一元-
            case 's':
                return 10000;
            case '*':
            case '/':
            case '%':
                return 1000;
            case '+':
            case '-':
                return 100;
            case '&':
            case '^':
                return 50;
            case ')':
                return -1;
            default:
                return 0;
        }
    }

注册操作

unordered_map<char, Operator*> RPN::opfunc_map {
        {'z', new UnaryAddOperator},
        {'y', new UnarySubOperator},
        {'+', new AddOperator},
        {'-', new SubOperator},
        {'*', new MultiplyOpeator},
        {'/', new DivideOperator},
        {'s', new SinOperator},
        {'&', new BitAndOperator},
};

计算器c++源码

#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <stack>
#include <string>
#include <math.h>

using namespace std;

/**** 基本计算器
 * 支持运算符
 * 一元运算符    特殊处理 - -> _     +直接删去
 * 二元运算符 + - * /
 * 特殊() [] {}
 * 扩充一元运算符
 * sin -> s
 * cos -> c
 * tan -> t
 *
 * 扩充二元运算符 |(二进制与) &(二进制或) ^(二进制异或)
 */

using OPTYPE = double;
int err_no = 0;

class Operator {
private:
    int cnt = 2;

    virtual OPTYPE cal(OPTYPE *buffer) = 0;

public:
    explicit Operator(int cnt) : cnt(cnt) {}

    virtual OPTYPE cal(stack<OPTYPE> &st) {
        if (st.size() < cnt) {
            cout << "st.size() < cnt";
            err_no = -1;
            return errno;
        }
        OPTYPE buffer[cnt];
        int idx = cnt;
        while (idx-- > 0) {
            buffer[idx] = st.top();
            st.pop();
        }
        return cal(buffer);
    }
};

class UnaryAddOperator : public Operator {
public:
    explicit UnaryAddOperator() : Operator(1) {}

private:
    OPTYPE cal(OPTYPE *buffer) override {
        return buffer[0];
    }
};

class UnarySubOperator : public Operator {
public:
    UnarySubOperator() : Operator(1) {}

private:
    OPTYPE cal(OPTYPE *buffer) override {
        return -buffer[0];
    }
};

class AddOperator : public Operator {
public:
    explicit AddOperator() : Operator(2) {}

private:
    OPTYPE cal(OPTYPE *buffer) override {
        return buffer[0] + buffer[1];
    }
};

class SubOperator : public Operator {
public:
    explicit SubOperator() : Operator(2) {}

private:
    OPTYPE cal(OPTYPE *buffer) override {
        return buffer[0] - buffer[1];
    }
};

class MultiplyOpeator : public Operator {
public:
    MultiplyOpeator() : Operator(2) {}

private:
    OPTYPE cal(OPTYPE *buffer) override {
        return buffer[0] * buffer[1];
    }
};

class DivideOperator : public Operator {
public:
    DivideOperator() : Operator(2) {}

private:
    OPTYPE cal(OPTYPE *buffer) override {
        return buffer[0] / buffer[1];
    }
};

class SinOperator : public Operator {
public:
    SinOperator() : Operator(1) {}

private:
    OPTYPE cal(OPTYPE *buffer) override {
        return sin(buffer[0]);
    }
};

class CosOperator : public Operator {
public:
    CosOperator() : Operator(1) {}

private:
    OPTYPE cal(OPTYPE *buffer) override {
        return cos(buffer[0]);
    }
};

class TanOperator : public Operator {
public:
    TanOperator() : Operator(1) {}

private:
    OPTYPE cal(OPTYPE *buffer) override {
        return tan(buffer[0]);
    }
};

class ModOperator : public Operator {
public:
    ModOperator() : Operator(2) {}

private:
    OPTYPE cal(OPTYPE *buffer) override {
        return (long long) buffer[0] % (long long) buffer[1];
    }
};

class BitAndOperator : public Operator {
public:
    BitAndOperator() : Operator(2) {}

private:
    OPTYPE cal(OPTYPE *buffer) override {
        if constexpr(sizeof(OPTYPE) == 8) {
            return (long long) buffer[0] & (long long) buffer[1];
        }
        return (int) buffer[0] & (int) buffer[1];
    }
};

class RPN {
private:
    static unordered_map<string, char> opname_map;

    static unordered_set<char> canMiss;


    string rpn;
    string result;
    static unordered_map<char, Operator *> opfunc_map;

    // 左结合运算符 取正
    // 右结合运算符取负, 目前只支持sin cos tan
    int priority(char op) {
        switch (op) {
            case '(':
                return 100000;
            case '!':
            case '~':
            case 'z':  // z --> 一元+
            case 'y':  // y --> 一元-
                return 10000;
            case '*':
            case '/':
            case '%':
                return 1000;
            case '+':
            case '-':
                return 100;
            case '&':
            case '^':
                return 50;
            case ')':
                return 0;
            case 's':
            case 't':
            case 'c':
                return -10000;
            default:
                return 0;
        }
    }

    // 特殊处理
    string formatSpecialFix(const string s) {
        string ans;
        bool has_num = false;
        for (int i = 0; i < s.size(); i++) {
            switch (s[i]) {
                case '+':
                case '-': {
                    bool unary = false;
                    if (i == 0) {
                        unary = true;
                    } else {
                        int j = i;
                        while (j - 1 >= 0 && canMiss.count(s[j - 1])) {
                            j--;
                        }
                        if (j - 1 >= 0 && s[j - 1] == '(') {
                            unary = true;
                        }
                    }
                    if (unary) {
                        string temp(1, s[i]);
                        ans.push_back(opname_map[temp]);
                    } else {
                        ans.push_back(s[i]);
                    }
                    break;
                }
                case 's':
                case 'c':
                case 't': {
                    if (i + 3 >= s.size()) {
                        err_no = -4;
                        cout << "bad op";
                        return "bad";
                    }
                    string temp = s.substr(i, 3);
                    if (opname_map.count(temp) == 0) {
                        err_no = -2;
                        cout << "op not exit";
                        return "bad";
                    }
                    ans.push_back(opname_map[temp]);
                    i += 2;
                    break;
                }
                default:
                    ans.push_back(s[i]);
            }
        }
        return ans;
    }

    void pop_until(char ch, stack<char> &st) {
        if (ch != '(' && priority(ch) < 0) {
            st.push(ch);
            return;
        }
        while (!st.empty() && st.top() != '(' && priority(st.top()) >= priority(ch)) {
            rpn.push_back(st.top());
            st.pop();
        }
        if (ch == ')') {
            st.pop();
        } else {
            st.push(ch);
        };
    }

public:
    string getResult() {
        return result;
    }

    void pn_to_rpn(const string &s) {
        string fixStr = formatSpecialFix(s);
        if (err_no != 0) {
            return;
        }
        cout << fixStr << endl;
        stack<char> st;
        for (int i = 0; i < fixStr.size(); i++) {
            if (canMiss.count(fixStr[i])) {
                continue;
            }
            if (isdigit(fixStr[i])) {
                rpn.push_back(fixStr[i]);
                while (i + 1 < fixStr.size() && (isdigit(fixStr[i + 1]) || fixStr[i + 1] == '.')) {
                    rpn.push_back(fixStr[i + 1]);
                    i++;
                }
            } else if (fixStr[i] == '(') {
                st.push(fixStr[i]);
                continue;
            } else {
                pop_until(fixStr[i], st);
            }
            rpn.push_back(' ');
        }
        while (!st.empty()) {
            rpn.push_back(st.top());
            st.pop();
        }
    }

    OPTYPE cal() {
        cout << rpn << endl;
        stack<OPTYPE> st;
        for (int i = 0; i < rpn.size(); i++) {
            // 空字符
            if (canMiss.count(rpn[i])) {
                continue;
            }
            // 数字
            if (isdigit(rpn[i])) {
                bool dot = false;
                double base = 0.1;
                OPTYPE value = rpn[i] - '0';
                while (i + 1 < rpn.size() && (isdigit(rpn[i + 1]) || rpn[i + 1] == '.')) {
                    if (rpn[i + 1] == '.') {
                        dot = true;
                    } else {
                        if (!dot) {
                            value = value * 10 + (rpn[i + 1] - '0');
                        } else {
                            value += ((rpn[i + 1] - '0') * base);
                            base /= 10;
                        }
                    }
                    i++;
                }
                st.push(value);
                continue;
            }
            if (opfunc_map.count(rpn[i]) == 0) {
                err_no = -3;
                cout << "unsupport op";
                break;
            }
            auto op = opfunc_map[rpn[i]];
            auto v = op->cal(st);
            if (err_no != 0) {
                break;
            }
            cout << v << endl;
            st.push(v);
        }
        if (err_no != 0) {
            return INT64_MIN;
        }
        cout << st.top() << endl;
        return st.top();
    }
};

unordered_map<string, char> RPN::opname_map{
        {"+",   'z'},
        {"-",   'y'},
        {"tan", 't'},
        {"sin", 's'},
        {"cos", 'c'},

};

unordered_set<char> RPN::canMiss{' '};

unordered_map<char, Operator *> RPN::opfunc_map{
        {'z', new UnaryAddOperator},
        {'y', new UnarySubOperator},
        {'+', new AddOperator},
        {'-', new SubOperator},
        {'*', new MultiplyOpeator},
        {'/', new DivideOperator},
        {'s', new SinOperator},
        {'c', new CosOperator},
        {'t', new TanOperator},
        {'%', new ModOperator},
        {'&', new BitAndOperator},
};

extern "C" {
OPTYPE calculate(const char *s) {
    err_no = 0;
    RPN rpn;
    rpn.pn_to_rpn(s);
    if (err_no != 0) {
        return INT64_MIN;
    }
    return rpn.cal();
}
}

//
int main() {
    cout << calculate("sincostan6");
}

python UI 源码

"""
实现带界面的计算器(可做加减乘除操作)

"""

from tkinter import *
import tkinter.font
from functools import partial

import ctypes
import platform

calculator = ctypes.CDLL('./cal.so')
calculator.calculate.restype = ctypes.c_double


def get_input(entry, argu):
    entry.insert(END, argu)


def backspace(entry):
    input_len = len(entry.get())
    entry.delete(input_len - 1)


def clear(entry):
    entry.delete(0, END)


def calc(entry):
    input = entry.get().strip()
    #output2 = str(eval(input))
    # print(output2)

    bs = ctypes.c_char_p(bytes(input, encoding="utf8"))
    output = calculator.calculate(bs)
    if output == -9223372036854775808:
        output = 'error'
    clear(entry)
    # if output2 != output:
    #    entry.insert(END, output)
    #    entry.insert(END, "\t")
    #    entry.insert(END, output2)
    # else:
    entry.insert(END, output)



def cal():
    root = Tk()
    root.title("我的计算器")
    root.resizable(0, 0)

    entry_font = tkinter.font.Font(size=12)
    entry = Entry(root, justify="right", font=entry_font)
    entry.grid(row=0, column=0, columnspan=4, sticky=N + W + S + E, padx=5, pady=5)

    button_font = tkinter.font.Font(size=10, weight=tkinter.font.BOLD)
    button_bg = '#D5E0EE'
    button_active_bg = '#E5E35B'

    myButton = partial(Button, root, bg=button_bg, padx=10, pady=3, activebackground=button_active_bg)

    button7 = myButton(text='7', command=lambda: get_input(entry, '7'))
    button7.grid(row=1, column=0, pady=5)

    button8 = myButton(text='8', command=lambda: get_input(entry, '8'))
    button8.grid(row=1, column=1, pady=5)

    button9 = myButton(text='9', command=lambda: get_input(entry, '9'))
    button9.grid(row=1, column=2, pady=5)

    button10 = myButton(text='+', command=lambda: get_input(entry, '+'))
    button10.grid(row=1, column=3, pady=5)

    button4 = myButton(text='4', command=lambda: get_input(entry, '4'))
    button4.grid(row=2, column=0, pady=5)

    button5 = myButton(text='5', command=lambda: get_input(entry, '5'))
    button5.grid(row=2, column=1, pady=5)

    button6 = myButton(text='6', command=lambda: get_input(entry, '6'))
    button6.grid(row=2, column=2, pady=5)

    button11 = myButton(text='-', command=lambda: get_input(entry, '-'))
    button11.grid(row=2, column=3, pady=5)

    button1 = myButton(text='1', command=lambda: get_input(entry, '1'))
    button1.grid(row=3, column=0, pady=5)

    button2 = myButton(text='2', command=lambda: get_input(entry, '2'))
    button2.grid(row=3, column=1, pady=5)

    button3 = myButton(text='3', command=lambda: get_input(entry, '3'))
    button3.grid(row=3, column=2, pady=5)

    button12 = myButton(text='*', command=lambda: get_input(entry, '*'))
    button12.grid(row=3, column=3, pady=5)

    button0 = myButton(text='0', command=lambda: get_input(entry, '0'))
    button0.grid(row=4, column=0, columnspan=1, padx=3, pady=5, sticky=N + S + E + W)

    button18 = myButton(text='%', command=lambda: get_input(entry, '%'))
    button18.grid(row=4, column=1, columnspan=1, padx=3, pady=5, sticky=N + S + E + W)

    button13 = myButton(text='.', command=lambda: get_input(entry, '.'))
    button13.grid(row=4, column=2, pady=5)

    button14 = Button(root, text='/', bg=button_bg, padx=10, pady=3,
                      command=lambda: get_input(entry, '/'))
    button14.grid(row=4, column=3, pady=5)

    button15 = Button(root, text='<-', bg=button_bg, padx=10, pady=3,
                      command=lambda: backspace(entry), activebackground=button_active_bg)
    button15.grid(row=5, column=0, pady=5)

    button16 = Button(root, text='C', bg=button_bg, padx=10, pady=3,
                      command=lambda: clear(entry), activebackground=button_active_bg)
    button16.grid(row=5, column=1, pady=5)

    button17 = Button(root, text='=', bg=button_bg, padx=10, pady=3,
                      command=lambda: calc(entry), activebackground=button_active_bg)
    button17.grid(row=5, column=2, columnspan=2, padx=3, pady=5, sticky=N + S + E + W)

    button19 = myButton(text='sin', command=lambda: get_input(entry, 'sin'))
    button19.grid(row=6, column=0, columnspan=1, padx=3, pady=5, sticky=N + S + E + W)

    button20 = myButton(text='cos', command=lambda: get_input(entry, 'cos'))
    button20.grid(row=6, column=1, columnspan=1, padx=3, pady=5, sticky=N + S + E + W)

    button21 = myButton(text='tan', command=lambda: get_input(entry, 'tan'))
    button21.grid(row=6, column=2, columnspan=2, padx=3, pady=5, sticky=N + S + E + W)

    button22 = myButton(text='(', command=lambda: get_input(entry, '('))
    button22.grid(row=7, column=0, columnspan=1, padx=3, pady=5, sticky=N + S + E + W)

    button23 = myButton(text=')', command=lambda: get_input(entry, ')'))
    button23.grid(row=7, column=1, columnspan=1, padx=3, pady=5, sticky=N + S + E + W)

    button24 = myButton(text='&', command=lambda: get_input(entry, '&'))
    button24.grid(row=7, column=2, columnspan=2, padx=3, pady=5, sticky=N + S + E + W)

    root.mainloop()


if __name__ == '__main__':
    cal()

c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现
c+±基本计算器的一般实现

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值