As the types of robots increase, the main program becomes more and more cumbersome, and the scalability and maintainability of the code are impacted. Even worse, if the performTask()
function is called in multiple places throughout the program, every time a new robot type is added, the program needs to be modified in several places. In a programmer village surrounded by code, three young programmers—Xiao Li, Xiao Zhang, and Xiao Wang—are busy solving a new problem: "How can we design a robot that can perform various tasks?" Whether it's cleaning, cooking, or repairing, they want the robot to switch tasks smoothly based on different needs. Just as they were puzzled, the concept of polymorphism brought them the solution.
Xiao Li's Initial Design: Let the Robot Perform Tasks
Xiao Li first proposed a simple idea: design a Robot
base class, from which all robots inherit, and use the performTask()
method to perform their respective tasks. His initial code was as follows:
class Robot { public: void performTask() { cout << "Robot is performing a general task!" << endl; } };
At first, this design seemed perfect. Each robot only needed to inherit from the Robot
base class and implement its own performTask()
method. Xiao Li created two subclasses: CleaningRobot
and CookingRobot
:
class CleaningRobot : public Robot { public: void performTask() { cout << "Cleaning robot is sweeping the floor!" << endl; } }; class CookingRobot : public Robot { public: void performTask() { cout << "Cooking robot is making dinner!" << endl; } };
Initially, Xiao Li thought the design was perfect. Each subclass could implement its own performTask()
method based on its role. But soon, he encountered a problem...
Problem: Difficulty in Modification and Expansion
As Xiao Li designed more types of robots, he began to realize that to add a new robot type (such as WashingRobot
or RepairRobot
), the main program had to be manually modified every time, adding new robot instances and calling their performTask()
methods.
For example, if a RepairRobot
is added, the main program might need to be changed as follows:
int main() { CleaningRobot cleaningRobot; CookingRobot cookingRobot; RepairRobot repairRobot; // New robot cleaningRobot.performTask(); cookingRobot.performTask(); repairRobot.performTask(); // New task return 0; }
As the number of robot types increases, the main program becomes more and more cumbersome, and the scalability and maintainability of the code are negatively impacted. Worse, if performTask()
is called in multiple places, every time a new robot type is added, it requires modification in multiple places.
Xiao Li sighed, "If only there were a way to avoid modifying the main program every time, and let the system automatically adapt to the new robot types as needed!"
Xiao Zhang’s Insight: Why Introduce Polymorphism
After much thought, Xiao Li finally expressed his concern: "Every time we add a new robot type, the main program has to be modified. This isn't very flexible. And as more robot types are added, the code will become more complicated."
Xiao Zhang nodded and smiled, saying, "What you're describing is exactly the limitation of traditional inheritance design. In your current design, the main program must know about every specific robot type, which increases the coupling between the code. Every time a new robot is added, the main program has to be modified. Actually, polymorphism can help us solve this problem."
Xiao Li was confused: "Then what's the difference between polymorphism and inheritance? Doesn't inheritance allow subclasses to inherit the functionality of their parent class? Why is inheritance alone not enough?"
Xiao Zhang patiently explained, "Inheritance does allow subclasses to inherit the functionality of the parent class, but it doesn't solve the problem of code depending on specific types. Specifically, through inheritance, the program still needs to explicitly know the type of each subclass. The essence of polymorphism is: through a base class pointer or reference, you can automatically call the correct subclass method at runtime based on the actual type of the object. In other words, the main program doesn't need to care about the object's specific type, it only cares about a unified interface."
Comparison: Ordinary Inheritance vs Polymorphism
Scalability and Maintainability
To help Xiao Li understand, Xiao Zhang gave an example. First, he showed the design without polymorphism:
int main() { CleaningRobot cleaningRobot; CookingRobot cookingRobot; RepairRobot repairRobot; // New robot cleaningRobot.performTask(); cookingRobot.performTask(); repairRobot.performTask(); // Every time a new task is added, the main program needs to be modified }
Xiao Zhang explained, "Look, without polymorphism, every time we add a new robot type (such as RepairRobot
), we need to modify the main program, manually add a new robot instance, and call its performTask()
method. This increases code coupling, making maintenance and expansion difficult."
Next, Xiao Zhang demonstrated the design with polymorphism:
class RepairRobot : public Robot { public: void performTask() { cout << "Repair robot is fixing things!" << endl; } }; int main() { Robot* robot1 = new CleaningRobot(); Robot* robot2 = new CookingRobot(); Robot* robot3 = new RepairRobot(); // New robot robot1->performTask(); robot2->performTask(); robot3->performTask(); delete robot1; delete robot2; delete robot3; return 0; }
"Through polymorphism, you see," Xiao Zhang continued, "we don't need to modify the main program at all. We just need to add a new RepairRobot
class and implement its own performTask()
method. The program will automatically select and call the corresponding performTask()
method based on the object's actual type. This greatly reduces the dependency between the main program and robot types, improving scalability and maintainability."
Unified Interface, Decoupling the Main Program
To further emphasize the advantages of polymorphism, Xiao Zhang explained how to reduce code redundancy through a unified interface. Without polymorphism, we might need to write different functions for each robot type:
void doSomethingWithRobot(CleaningRobot& robot) { robot.performTask(); } void doSomethingWithRobot(CookingRobot& robot) { robot.performTask(); }
"Every time we add a new robot type, we have to write a new function," Xiao Zhang said. "This not only makes the code lengthy but also leads to more complicated maintenance."
But with polymorphism, things become simpler. We only need to write one function:
void doSomethingWithRobot(Robot* robot) { robot->performTask(); }
"Look," Xiao Zhang continued, "with polymorphism, no matter how many robot types we add, the main program doesn't need to change. The main program and the specific implementation are decoupled, making the code more concise and easier to maintain."
Note: Whether using inheritance or polymorphism, when adding a new robot, you still need to create a new class and implement the corresponding interface. The difference is that, with inheritance, the main program must explicitly add a new robot instance and call its method. With polymorphism, the main program almost doesn't need to change, and the new robot type can automatically adapt.
Implementing Polymorphism: Key Points
Finally, Xiao Zhang summarized: "To implement polymorphism, the key is to declare the performTask()
method of the base class as virtual
, so the program can correctly call the overridden method of the subclass at runtime."
class Robot { public: virtual void performTask() { cout << "Robot is performing a general task!" << endl; } virtual ~Robot() { } // Ensure the base class has a virtual destructor }; class CleaningRobot : public Robot { public: void performTask() { cout << "Cleaning robot is sweeping the floor!" << endl; } }; class CookingRobot : public Robot { public: void performTask() { cout << "Cooking robot is making dinner!" << endl; } };
By using the virtual
keyword, the performTask()
method of the base class becomes a virtual function, and the overridden performTask()
method of the subclass will be correctly called at runtime. This is how polymorphism is implemented, making the program's extension and maintenance more flexible and efficient.
Xiao Wang’s Addition: How to Use Polymorphism?
Through the previous explanation, you now understand the basic concept of polymorphism: through a base class pointer, we can dynamically select which subclass method to call at runtime. Xiao Wang added, "The key to polymorphism is that, through a base class pointer or reference, we can call a unified interface without worrying about the specific subclass implementation."
Example code:
int main() { Robot* robot1 = new CleaningRobot(); Robot* robot2 = new CookingRobot(); robot1->performTask(); // Output: Cleaning robot is sweeping the floor! robot2->performTask(); // Output: Cooking robot is making dinner! delete robot1; delete robot2; return 0; }
In this example, robot1 and robot2 point to objects of type CleaningRobot and CookingRobot respectively. When we call the performTask() method through the base class pointer Robot*, the program will automatically select the correct method implementation based on the actual object type. Even if we do not explicitly specify the subclass type, the program can still correctly perform different tasks.
This is the advantage of polymorphism: the main program does not need to care about the specific type of each robot object, it only needs to call it through the base class interface. In this way, the program is decoupled from the specific subclass, greatly improving the flexibility and maintainability of the code.
Xiao Li's Gains: Advantages of Polymorphism
Xiao Li summarized several key advantages brought by polymorphism:
Unified interface: calling methods through the base class interface, the main program does not need to care about the specific subclass type. Whether it is CleaningRobot or CookingRobot, tasks can be performed through the same interface, simplifying the code.
Strong scalability: When we need to add a new robot type, we only need to create a new subclass and implement the necessary methods, and the main program code does not need to be modified. The program will automatically adapt to the newly added subclass, greatly improving the scalability and flexibility of the code.
Summary: The magic of polymorphism
Through Xiao Li's exploration and Xiao Zhang and Xiao Wang's supplement, we have mastered the basic concept of polymorphism: through the base class pointer or reference, the program can automatically choose to call different subclass methods at runtime. This not only makes the structure of the program more concise, but also greatly improves the flexibility and scalability of the code.
As we can see, no matter how many types of robots increase, the main structure of the program hardly needs to be modified. The newly added robots only need to implement the interface defined by the base class, and the program can automatically adapt. This feature makes polymorphism a powerful tool for code reuse and decoupling, helping us to cope with changing needs more easily.
This is the charm of polymorphism: it makes our code more modular, easy to expand and maintain. In the next article, we will further explore the implementation principle of polymorphism and reveal how it works at compile and run time.