题目
编写程序,演示面向对象的核心精髓——多态(Polymorphism)。设计几何图形基类 Shape 与派生类 Circle、Rectangle。通过对比普通非虚函数(编译期静态早绑定 Early Binding,由指针类型决定调用)与 virtual 虚函数(运行时动态晚绑定 Late Binding,由实际指向的对象真实类型决定调用);使用基类指针数组统一管理多态图形对象,循环触发各自重写的绘制逻辑。
输入格式:无需外部输入。
输出格式:输出基类指针调用虚函数时各派生类具体重写逻辑的回显日志。
数据范围与约定:虚函数机制、静态绑定与动态多态分发。
思路与算法
1. 静态绑定的局限
若成员函数未标记 virtual,当使用 Shape* p = new Circle(); p->draw(); 时,编译器仅根据 p 的声明类型(Shape*)在编译期直接硬编码调用 Shape::draw(),丧失多态扩展能力。
2. virtual 的动态分发
标记 virtual 后,编译器通过对象的虚函数表指针(vptr)在运行时跳转寻址,从而准确命中 Circle::draw()。
3. 多态成立的两大硬性条件
①必须通过父类的指针或引用来调用;②被调用的函数必须在基类中被声明为 virtual。
完整程序
#include <iostream>
#include <vector>
#include <memory>
class Shape {
public:
// 普通函数:静态早绑定
void identify() const {
std::cout << "[静态绑定] 我是一个普通的几何图形 Shape\n";
}
// 虚函数:运行时动态晚绑定
virtual void draw() const {
std::cout << "[动态绑定] 绘制 Shape 基础轮廓\n";
}
virtual ~Shape() = default; // 虚析构函数保证释放安全
};
class Circle : public Shape {
public:
void draw() const override {
std::cout << "[Circle 多态绘制] 正在绘制圆形 ◯ (基于半径与圆心)\n";
}
};
class Rectangle : public Shape {
public:
void draw() const override {
std::cout << "[Rectangle 多态绘制] 正在绘制矩形 ▭ (基于长宽网格)\n";
}
};
int main() {
Circle c;
Rectangle r;
// 1. 基类指针多态集合
std::vector<Shape*> canvas = {&c, &r};
std::cout << "--- 1. 测试静态绑定 identify() ---\n";
for (Shape* s : canvas) {
s->identify(); // 无论底层是 Circle 还是 Rectangle,均静态调用 Shape::identify
}
std::cout << "\n--- 2. 测试 virtual 动态多态 draw() ---\n";
for (Shape* s : canvas) {
s->draw(); // 运行时动态分发,分别调用 Circle::draw 与 Rectangle::draw
}
return 0;
}运行示例
输出:
--- 1. 测试静态绑定 identify() ---
[静态绑定] 我是一个普通的几何图形 Shape
[静态绑定] 我是一个普通的几何图形 Shape
--- 2. 测试 virtual 动态多态 draw() ---
[Circle 多态绘制] 正在绘制圆形 ◯ (基于半径与圆心)
[Rectangle 多态绘制] 正在绘制矩形 ▭ (基于长宽网格)