罗马数字与整数混合计算器C++开发求助:构造函数与转换问题
Hey there! Let's work through this Roman numeral calculator problem you're stuck on. It sounds like you've got the Roman class and operator overloading started, but the type conversion and constructor bits are tripping you up—let's break this down with practical code and explanations.
First, Let's Solidify the Roman Class Structure
Since you need to support both int and string inputs, your dual constructors are the right starting point. The key is to store a single integer value internally (since all arithmetic will happen on integers anyway), and handle the <-> Roman string conversion in helper functions. Here's a robust implementation:
#include <string> #include <unordered_map> #include <vector> #include <stdexcept> #include <iostream> class Roman { private: int numericValue; // Core storage: all operations use this int // Helper maps for conversion logic static const std::unordered_map<char, int> romanCharToInt; static const std::vector<std::pair<int, std::string>> intToRomanPairs; // Convert Roman string to int (private helper) int strToInt(const std::string& romanStr) const { int result = 0; for (size_t i = 0; i < romanStr.size(); ++i) { // Handle subtractive combinations (IV, IX, etc.) if (i < romanStr.size() - 1 && romanCharToInt.at(romanStr[i]) < romanCharToInt.at(romanStr[i+1])) { result -= romanCharToInt.at(romanStr[i]); } else { result += romanCharToInt.at(romanStr[i]); } } return result; } // Convert int to Roman string (private helper) std::string intToStr(int num) const { std::string result; for (const auto& pair : intToRomanPairs) { while (num >= pair.first) { result += pair.second; num -= pair.first; } } return result; } public: // Constructor 1: Accept an integer Roman(int num) { // Validate Roman numeral range (1-3999 is standard) if (num < 1 || num > 3999) { throw std::invalid_argument("Roman numerals only support values 1-3999"); } numericValue = num; } // Constructor 2: Accept a Roman numeral string Roman(const std::string& romanStr) : numericValue(strToInt(romanStr)) { // Optional: Add validation here to ensure the input string is a valid Roman numeral } // Type conversion: Roman -> int (critical for mixed operations) operator int() const { return numericValue; } // Overload core arithmetic operators (Roman + Roman) Roman operator+(const Roman& other) const { return Roman(numericValue + other.numericValue); } Roman operator-(const Roman& other) const { return Roman(numericValue - other.numericValue); } // Support mixed operations (int + Roman, Roman + int) friend Roman operator+(int lhs, const Roman& rhs) { return Roman(lhs + rhs.numericValue); } friend Roman operator-(int lhs, const Roman& rhs) { return Roman(lhs - rhs.numericValue); } // Optional: Overload output to print Roman strings instead of integers friend std::ostream& operator<<(std::ostream& os, const Roman& roman) { os << roman.intToStr(roman.numericValue); return os; } }; // Initialize static conversion maps const std::unordered_map<char, int> Roman::romanCharToInt = { {'I', 1}, {'V', 5}, {'X', 10}, {'L', 50}, {'C', 100}, {'D', 500}, {'M', 1000} }; const std::vector<std::pair<int, std::string>> Roman::intToRomanPairs = { {1000, "M"}, {900, "CM"}, {500, "D"}, {400, "CD"}, {100, "C"}, {90, "XC"}, {50, "L"}, {40, "XL"}, {10, "X"}, {9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"} };
Key Fixes for Your Type Conversion & Constructor Issues
Avoid Explicit Constructors (Unless You Have To)
If yourintconstructor uses theexplicitkeyword, the compiler can't implicitly convert integers to Roman objects for mixed operations (like5 + Roman("X")). Since yourmain()function can't change, skipexplicithere to allow seamless implicit conversion.Implement the Roman-to-Int Conversion Operator
Theoperator int() constmethod lets you convert a Roman object back to an integer, which is essential if yourmain()code expects to use Roman values in integer contexts (e.g.,int result = Roman("III") + 2;).Handle Mixed Operations with Friend Operators
While implicit conversion works for most cases, explicitly overloading friend operators likeoperator+(int, const Roman&)eliminates ambiguity and makes your code more readable. This ensures operations like10 + Roman("V")work without compiler errors.Validate Inputs
Adding range checks to theintconstructor prevents invalid values (like 0 or 4000) from breaking your conversion logic. You can also add validation to the string constructor to reject invalid Roman numerals (e.g., "IIII" or "VX").
Testing with an Unchanged main()
If your main() looks something like this, the above code will work perfectly:
int main() { Roman r1("X"); Roman r2(5); Roman sum = r1 + r2; Roman diff = 15 - r1; std::cout << "X + 5 = " << sum << std::endl; // Prints "XV" std::cout << "15 - X = " << diff << std::endl; // Prints "V" int numericSum = r1 + 3; // numericSum = 13 return 0; }
内容的提问来源于stack exchange,提问作者canntsn




