基于多态实现根据用户输入调用对应进制转换函数
Let's fix your code step by step to implement a clean polymorphic solution for converting numbers from different bases to decimal. Here's what we need to address:
Key Issues in Your Original Code
- You can't instantiate an abstract base class (like
Base) directly because it contains pure virtual functions (marked with=0). - The
toDecfunction wasn't properly designed for polymorphism—it should be a pure virtual function that each derived class implements. - Derived classes (
Hex,Binary) didn't have constructors to initialize the base class correctly. - You needed a way to dynamically create the right derived class instance based on user input (a factory pattern).
Revised Implementation
Step 1: Refactor the Abstract Base Class
First, we'll define a clean interface with a pure virtual toDec function and a virtual destructor (critical for proper memory cleanup when using polymorphism):
#include <iostream> #include <string> #include <cstdlib> // For strtoull #include <memory> // For smart pointers (optional but recommended) using namespace std; class Base { public: Base(string n, string b) : number(n), base(b) {} virtual ~Base() = default; // Virtual destructor to ensure proper cleanup virtual double toDec() const = 0; // Pure virtual: must be implemented by derived classes protected: string number; // The number string in the original base string base; // The base type (e.g., "hex", "binary") };
Step 2: Implement Derived Classes
Each derived class will handle its own conversion to decimal. We'll use strtoull (string to unsigned long long) with the appropriate base parameter:
class Hex : public Base { public: Hex(string n) : Base(n, "hex") {} // Initialize base class with number and "hex" double toDec() const override { char* endPtr; // Convert hex string to unsigned long long, then cast to double unsigned long long decimalVal = strtoull(number.c_str(), &endPtr, 16); return static_cast<double>(decimalVal); } }; class Binary : public Base { public: Binary(string n) : Base(n, "binary") {} // Initialize base class with number and "binary" double toDec() const override { char* endPtr; // Convert binary string to unsigned long long, then cast to double unsigned long long decimalVal = strtoull(number.c_str(), &endPtr, 2); return static_cast<double>(decimalVal); } };
Step 3: Factory Function for Dynamic Object Creation
This function takes the user's input (number and base type) and returns a pointer to the correct derived class instance. This is how we achieve dynamic polymorphism without cluttering the main logic with if/switch (the logic is isolated to the factory):
// Using unique_ptr to avoid memory leaks (recommended) unique_ptr<Base> createNumber(const string& number, const string& baseType) { if (baseType == "hex") { return make_unique<Hex>(number); } else if (baseType == "binary") { return make_unique<Binary>(number); } // Add more base cases here (e.g., "decimal", "octal") return nullptr; // Return null if base type is unknown }
Step 4: Main Function
Now we can use the factory function to dynamically create the right object and call toDec() polymorphically:
int main() { string number, baseType; cout << "Enter number and base (e.g., 1A hex or 1010 binary): "; cin >> number >> baseType; unique_ptr<Base> num = createNumber(number, baseType); if (num) { cout << "Decimal value: " << num->toDec() << endl; } else { cout << "Error: Unknown base type!" << endl; } return 0; }
Why This Works
- Polymorphism: When we call
num->toDec(), the correct implementation (fromHexorBinary) is invoked at runtime based on the actual object type. - Abstract Base Class: Enforces that all derived classes implement
toDec(), ensuring a consistent interface. - Factory Pattern: Isolates the logic of creating objects, making it easy to add new bases (like Octal) later without changing the main code.
Notes
- Error Handling: The current code assumes valid input. You might want to add checks (e.g., ensure hex strings only contain valid characters 0-9, A-F).
- Smart Pointers: Using
unique_ptrautomatically manages memory, so you don't have to manuallydeleteobjects (avoiding memory leaks). - Alternative Conversion: If you need to handle larger numbers or floating points, you could adjust the
toDecreturn type or use different conversion functions.
内容的提问来源于stack exchange,提问作者mhm

