В настоящее время я реализую научный калькулятор, используя MFC и C++.
Я завершил большую часть функциональности, но все еще работаю над функцией скобок.
Процесс ввода в поле ввода совершенно беспроблемный.
Если я наберу 5+5 без скобок, я получу 10.
Однако когда я помещаю число в круглые скобки, оно рассматривается как ноль. Например, я получаю (5)+5= 5.
Я потратил много времени на размышления об этом, поиск в Google и вопрос GPT, но не могу получить ответ.
Пожалуйста, дайте мне знать, если я что-то пропустил или сделал неправильно, спасибо.
Мой код:
void CMFCApplication20Dlg::OnBnClickedButtonLeftParen()
{
CString temp;
GetDlgItem(IDC_STATIC_VIEW)->GetWindowText(temp);
temp += _T("("); // 왼쪽 괄호 추가
SetDlgItemText(IDC_STATIC_VIEW, temp);
m_LeftParenCount++;
}
void CMFCApplication20Dlg::OnBnClickedButtonRightParen()
{
CString temp;
GetDlgItem(IDC_STATIC_VIEW)->GetWindowText(temp);
if (m_LeftParenCount > m_RightParenCount)
{
temp += _T(")"); // 오른쪽 괄호 추가
SetDlgItemText(IDC_STATIC_VIEW, temp);
m_RightParenCount++;
}
else
{
AfxMessageBox(_T("Cannot add right parenthesis. Mismatched parentheses."));
}
}
void CMFCApplication20Dlg::OnBnClickedButtonEquals()
{
CString temp;
GetDlgItem(IDC_STATIC_VIEW)->GetWindowText(temp);
m_LeftParenCount = 0;
m_RightParenCount = 0;
AfterData = _ttof(temp); // 지수값(추가함)
// CString을 double로 변환 (소수점 지원)
double result = 0.0;
double beforeData = _ttof(ViewStrData); // ViewStrData를 CString에서 double로 변환
double afterData = _ttof(temp); // temp를 CString에서 double로 변환
// % 코드임
int percentPos = temp.Find(_T("%"));
if (percentPos != -1)
{
// `%` 기호가 있을 경우, 해당 기호를 기준으로 문자열 분리
CString numberStr = temp.Left(percentPos); // '%' 기호 이전 부분
double number = _ttof(numberStr); // 문자열을 double로 변환
double result = number / 100.0;
// 결과를 문자열로 변환하고 IDC_STATIC_VIEW에 표시
CString resultStr;
resultStr.Format(_T("%.2f"), result);
SetDlgItemText(IDC_STATIC_RESULT, resultStr);
ChangeCheck = true;
Sign = 0;
return;
}
// 계산 로직
switch (Sign)
{
case 1: result = beforeData + afterData; break;
case 2: result = beforeData - afterData; break;
case 3: result = beforeData * afterData; break;
case 4:
if (afterData != 0.0)
result = beforeData / afterData;
else
{
AfxMessageBox(_T("Zero division error!"));
return;
}
break;
case 5:
if (afterData != 0.0)
result = fmod(beforeData, afterData);
else
AfxMessageBox(_T("Zero division error!"));
break;
// 추가적인 연산자 처리...
default: AfxMessageBox(_T("Invalid operation!")); return;
}
// 결과를 결과 창에 표시
UpdateResultView(result);
GetDlgItem(IDC_STATIC_VIEW)->SetWindowText(_T(""));
ChangeCheck = true;
Sign = 0;
}
Несколько общих советов: (1) Отделите бизнес-логику от графического пользовательского интерфейса, (2) графический интерфейс гораздо проще писать на C#, а интерфейс с движком C++ осуществляется через C++/CLI.
Спасибо за совет. Мои клиенты используют MFC, поэтому и мне следует тоже.
Если строки содержат (5)
, функция _ttof
(или atof
) не обработает это. Вместо этого вы получите 0.0
в качестве результата.
Кроме того, все эти _T
и _t
были добавлены, чтобы вы могли скомпилировать одну и ту же базу кода как с Windows 95, так и с Windows NT. Если это не ваша цель, вы можете просто использовать char
или wchar_t
и пропустить все трюки с макросами.
Обычно первым шагом является анализ входных данных в абстрактном синтаксическом дереве (AST), а затем выполнение вычислений в AST. Есть несколько вариантов первого шага: мне в голову пришло усиление духа или бизона. Графический интерфейс должен быть просто делегирован для взаимодействия с пользователем (подготовка ввода и отображение вывода).
Вероятно, вы захотите использовать алгоритм сортировочной станции.
Основная проблема заключается в этой строке кода:
AfterData = _ttof(temp);
Макрос, похожий на функцию _ttof
, расширяется до atof
или _wtof
(в зависимости от символов препроцессора _MBCS
и _UNICODE
). Любая функция документирована для выполнения следующей операции:
Каждая функция возвращает значение
double
, полученное путем интерпретации входных символов как числа. Возвращаемое значение равно 0,0, если входные данные невозможно преобразовать в значение этого типа.
При передаче "5"
в качестве входных данных функции точно преобразуют его в значение 5.0
. Однако с "(5)"
дела обстоят иначе. Хотя люди могут легко увидеть, что круглые скобки избыточны и не влияют на значение, функции преобразования не пытаются (математически) интерпретировать входные данные. Они просто продолжают читать первый символ ('('
) и выдают ошибку, поскольку это недопустимый символ в литерале с плавающей запятой.
Вместо этого вам придется написать токенизатор и анализатор, способный интерпретировать математические выражения в (предположительно) инфиксной записи. Алгоритм сортировочной станции — широко известное решение проблемы синтаксического анализа. Как отметил в комментариях , на YouTube есть видео, в котором достаточно подробно объясняется алгоритм: Язык программирования своими руками №1: Алгоритм сортировочной станции.
Если вам нужна дополнительная помощь, я могу написать начальную реализацию, чтобы вы могли начать.
Мой совет: сначала напишите отдельную библиотеку C++, в которой вы сможете использовать std::string и т. д. для реализации бизнес-логики вашего калькулятора. Затем напишите модульные тесты для отладки синтаксического анализа вашего
(5)+5
кода и отладьте его! Добавление пользовательского интерфейса MFC или его отсутствие — это то, что всегда следует делать в последнюю очередь. И мне любопытно, почему CMFC вообще для пользовательского интерфейса? (Это древнее)