#include <iostream>
#include <string>
#include <limits>
// 操作类型枚举(C++11强类型枚举)
enum class Operation { Add, Subtract, Multiply, Divide, Unknown };
// 异常类型枚举
enum class CalcError { DivisionByZero, InvalidInput };
// 打印欢迎界面
void print_welcome() {
std::cout << "========== 简易计算器 ==========\n"
<< "支持运算符: + - * /\n"
<< "输入格式: 数字1 运算符 数字2\n"
<< "示例: 12.5 + 3.14\n"
<< "输入 q 退出程序\n"
<< "================================\n";
}
// 解析运算符(C++17 string_view优化)
Operation parse_operator(std::string_view op) {
if (op == "+") return Operation::Add;
if (op == "-") return Operation::Subtract;
if (op == "*") return Operation::Multiply;
if (op == "/") return Operation::Divide;
return Operation::Unknown;
}
// 执行计算并返回结果(C++17 nodiscard属性)
[[nodiscard]] double calculate(double num1, Operation op, double num2) {
switch (op) {
case Operation::Add: return num1 + num2;
case Operation::Subtract: return num1 - num2;
case Operation::Multiply: return num1 * num2;
case Operation::Divide:
if (num2 == 0) throw CalcError::DivisionByZero;
return num1 / num2;
default:
throw CalcError::InvalidInput;
}
}
// 处理用户输入(返回是否继续执行)
bool process_input() {
std::cout << ">>> ";
std::string input;
if (!std::getline(std::cin, input) || input == "q") {
return false;
}
try {
// 使用string流解析输入
std::istringstream iss(input);
double num1, num2;
std::string op_str;
if (!(iss >> num1 >> op_str >> num2)) {
throw CalcError::InvalidInput;
}
// 清理多余输入
if (iss.rdbuf()->in_avail() != 0) {
throw CalcError::InvalidInput;
}
Operation op = parse_operator(op_str);
double result = calculate(num1, op, num2);
// 设置输出精度
std::cout.precision(2);
std::cout << "结果: " << std::fixed << result << "\n";
} catch (CalcError error) {
switch (error) {
case CalcError::DivisionByZero:
std::cerr << "错误:除数不能为零\n";
break;
case CalcError::InvalidInput:
std::cerr << "错误:无效输入格式\n";
break;
}
// 清除错误状态
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
return true;
}
int main() {
print_welcome();
while (process_input()) {}
std::cout << "感谢使用计算器!\n";
return 0;
}
代码亮点解析
- 现代C++特性应用
enum class
强类型枚举提升安全性std::string_view
优化字符串处理[[nodiscard]]
属性防止结果丢失std::istringstream
安全解析输入
- 防御性编程策略
- 完整输入格式校验
- 除零错误检测
- 输入流清理机制
- 异常处理框架
- 用户体验优化
- 友好的欢迎界面
- 持续交互循环
- 精确结果输出
- 明确的错误提示
功能扩展建议
- 增强计算能力
// 添加幂运算支持
case Operation::Power:
return std::pow(num1, num2);
// 添加取模运算
case Operation::Mod:
if (num2 == 0) throw CalcError::DivisionByZero;
return std::fmod(num1, num2);
- 历史记录功能
std::vector<std::string> history;
// 在计算成功后添加
history.push_back(std::to_string(num1) + " " + op_str + " "
+ std::to_string(num2) + " = " + std::to_string(result));
- 科学计算模式
void scientific_mode() {
// 实现三角函数、对数等计算
// 示例:sin函数计算
double angle;
std::cout << "输入角度值: ";
std::cin >> angle;
std::cout << "sin(" << angle << ") = " << std::sin(angle * M_PI / 180);
}
常见问题解答
Q:如何处理连续运算(如1+2*3)? A:需要实现以下改进:
- 使用逆波兰表达式算法
- 添加运算符优先级处理
- 实现表达式解析器
Q:如何支持变量存储? A:扩展方案:
std::map<std::string, double> variables;
// 输入示例:x = 5
// 存储变量后可在表达式中使用
Q:为什么推荐使用string流解析输入? A:相比直接使用cin的优点:
- 更好的错误恢复能力
- 支持整行输入处理
- 方便格式验证
注意事项
- 输入验证要点
- 检查数值范围(防止溢出)
- 过滤非法字符
- 处理多余空格
- 验证运算符有效性
- 精度问题处理
// 比较浮点数应使用epsilon方法
bool is_equal(double a, double b) {
return std::abs(a - b) < std::numeric_limits<double>::epsilon();
}
- 跨平台兼容性
- Windows换行符处理(\r\n)
- 本地化数字格式适配(如逗号小数点)
- 终端编码兼容(支持中文提示)
本计算器项目完整展示了基础语法在实际开发中的综合应用,后续可通过以下方向深化学习:
- 学习使用CMake管理项目
- 添加单元测试(Google Test)
- 实现GUI界面(Qt框架)
- 研究表达式解析算法(逆波兰、递归下降)