意表を突いても勝てない

サンムーンでたら頑張る

C++で電卓

今までCしか書いたことなかったけどC++やることになったので、
電卓をクラスとか使ってC++っぽく書いてみた。
参考というかほぼこちらのコードを使用
blog.goo.ne.jp


CCalc.cpp

#include <cctype>//isdigit
#include <cmath>// round,fabs
#include <cfloat>//DBL_EPSILON
#include "CCalc.h"



long  CCalc::getErrorCode() {
	return m_errorCode;
}

double CCalc::calculate() {

	return AddSub();
}

double CCalc::AddSub()
{
	double ans = MulDiv();
	
	while ((m_errorCode != ERRCODE_BAD) && (m_itr != m_inputString.end())) {
		switch (*m_itr) {
			case '+':
				m_itr++;
				ans += MulDiv();
				break;
			case '-':
				m_itr++;
				ans -= MulDiv();
				break;
			default:
				if (!isdigit(*m_itr) && (*m_itr != '.')) {//数字の後の数字意外を弾く(例:5g4)
					m_errorCode = ERRCODE_BAD;
				}
				return ans;
				break;

		}
	}
	return ans;
}

double CCalc::MulDiv()
{
	double ans = Factor();
	double div = 0.0; //割る数が0以外かのチェック用
	while ((m_errorCode != ERRCODE_BAD) && (m_itr!= m_inputString.end())) {
		switch (*m_itr) {
		case '*':
			m_itr++;
			ans *= Factor();
			break;
		case '/':
			m_itr++;
			div = Factor();
			if (fabs(div - 0.0) < DBL_EPSILON) {//小数なので相対誤差で0かチェック
				m_errorCode = ERRCODE_BAD;
				return ans;
			}
			ans /= div;
			break;
		default:
			return ans;
			break;
		}
	}
	return ans;
}

double CCalc::Factor()
{
	if (isdigit(*m_itr) || (*m_itr == '.')) {
		return Value();
	}
	m_errorCode = ERRCODE_BAD;//1文字目,演算子の後が数字じゃなければエラー

	return 0;
}

double CCalc::Value()
{	
	double ans = 0.0;
	size_t conversion_i = 0;
	ans = std::stod(&(*m_itr), &conversion_i);
	m_itr += conversion_i;
	ans = round2(ans, m_DEGREE);//入力を5桁に調整
	return ans;
}

double CCalc::round2(double dIn, int nLen)
{
	double    dOut;

	dOut = dIn * pow(10.0, nLen-1);
	dOut = (double)round(dOut);
	dOut *= pow(10.0, -(nLen-1));

	return dOut;
}

CCalc.h

#pragma once
#include <string>
using namespace std;

class CCalc
{
public:
	CCalc() = delete;
	CCalc(const string& input) : m_inputString(input),m_errorCode(ERRCODE_SUCCESS){
		m_itr = m_inputString.begin();
	}
	virtual ~CCalc() = default;

	enum eERRCODE {
		ERRCODE_SUCCESS,
		ERRCODE_BAD,
	};

	long getErrorCode();
	double calculate();


private:
	const string m_inputString;
	long m_errorCode;
	string::const_iterator m_itr;
	static const int m_DEGREE = 6;//四捨五入をする桁←どこで書くべき?

	double AddSub();
	double MulDiv();
	double Factor();
	double Value();
	double round2(double dIn, int nLen);
};


main.cpp

#include <iostream>
#include <iomanip>
#include <string>
#include "CCalc.h"

using namespace std;

int main(void)
{
	string input;
	
	while (!cin.eof()) {
		cin >> input;
		if (input != "\0") {

			CCalc calc(input);//new~Deleteにするかセット関数にするか,このままだとインスタンスをずっと生成してしまう?

			double ans = calc.calculate();
		
			switch ( calc.getErrorCode() ) {
				case calc.ERRCODE_BAD:
					cout << "ERROR!" << endl << endl;
					break;
				default:
					cout << fixed << setprecision(5) << ans <<endl << endl;//小数点5桁表示
			}
		}
	}
	return 0;
}