题目

编写程序,演示面向对象的核心精髓——多态(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 多态绘制] 正在绘制矩形 ▭ (基于长宽网格)