You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

罗马数字与整数混合计算器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

  1. Avoid Explicit Constructors (Unless You Have To)
    If your int constructor uses the explicit keyword, the compiler can't implicitly convert integers to Roman objects for mixed operations (like 5 + Roman("X")). Since your main() function can't change, skip explicit here to allow seamless implicit conversion.

  2. Implement the Roman-to-Int Conversion Operator
    The operator int() const method lets you convert a Roman object back to an integer, which is essential if your main() code expects to use Roman values in integer contexts (e.g., int result = Roman("III") + 2;).

  3. Handle Mixed Operations with Friend Operators
    While implicit conversion works for most cases, explicitly overloading friend operators like operator+(int, const Roman&) eliminates ambiguity and makes your code more readable. This ensures operations like 10 + Roman("V") work without compiler errors.

  4. Validate Inputs
    Adding range checks to the int constructor 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

火山引擎 最新活动