MST

星途 面试题库

面试题:C++ 多态如何助力代码扩展性之实例分析

请以一个简单的图形绘制程序为例,说明如何利用C++的多态性来实现代码扩展性。假设程序需要支持绘制圆形、矩形和三角形,每个图形都有绘制函数 `draw()`,请编写代码展示如何运用多态实现这一功能,并解释多态是如何让添加新图形变得容易的。
47.9万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 定义基类

    class Shape {
    public:
        virtual void draw() const = 0;
    };
    

    这里定义了一个抽象基类 Shape,其中包含一个纯虚函数 draw()。纯虚函数使得 Shape 类成为抽象类,不能被实例化,其目的是为所有具体的图形类提供一个统一的接口。

  2. 定义具体图形类

    • 圆形
    class Circle : public Shape {
    public:
        void draw() const override {
            std::cout << "Drawing a circle." << std::endl;
        }
    };
    
    • 矩形
    class Rectangle : public Shape {
    public:
        void draw() const override {
            std::cout << "Drawing a rectangle." << std::endl;
        }
    };
    
    • 三角形
    class Triangle : public Shape {
    public:
        void draw() const override {
            std::cout << "Drawing a triangle." << std::endl;
        }
    };
    

    这些具体的图形类都继承自 Shape 类,并实现了 draw() 函数。override 关键字用于显式表明该函数是重写基类的虚函数,增加代码的可读性和可维护性。

  3. 使用多态

    #include <iostream>
    #include <vector>
    
    int main() {
        std::vector<Shape*> shapes;
        shapes.push_back(new Circle());
        shapes.push_back(new Rectangle());
        shapes.push_back(new Triangle());
    
        for (const auto& shape : shapes) {
            shape->draw();
        }
    
        for (const auto& shape : shapes) {
            delete shape;
        }
    
        return 0;
    }
    

    main 函数中,创建了一个 Shape 指针的向量。将不同具体图形类的对象指针加入到这个向量中。通过遍历这个向量,调用 draw() 函数,根据指针实际指向的对象类型,调用相应图形类的 draw() 函数,这就是多态的体现。

  4. 多态如何让添加新图形变得容易

    • 代码修改量小:若要添加新图形,比如 Square。只需定义一个新的类 Square 继承自 Shape 类,并实现 draw() 函数。
    class Square : public Shape {
    public:
        void draw() const override {
            std::cout << "Drawing a square." << std::endl;
        }
    };
    
    • 不影响现有代码:在 main 函数中,只需像添加其他图形一样,将 Square 对象的指针加入到 shapes 向量中,而无需修改现有图形类的代码和 draw() 函数调用的逻辑。
    int main() {
        std::vector<Shape*> shapes;
        shapes.push_back(new Circle());
        shapes.push_back(new Rectangle());
        shapes.push_back(new Triangle());
        shapes.push_back(new Square());
    
        for (const auto& shape : shapes) {
            shape->draw();
        }
    
        for (const auto& shape : shapes) {
            delete shape;
        }
    
        return 0;
    }
    

    这样,通过多态,添加新图形变得简单且不会对现有代码造成较大影响,提高了代码的扩展性。

上述代码使用了动态内存分配,在实际应用中可以考虑使用智能指针来管理内存,以避免内存泄漏。例如:

#include <iostream>
#include <vector>
#include <memory>

class Shape {
public:
    virtual void draw() const = 0;
};

class Circle : public Shape {
public:
    void draw() const override {
        std::cout << "Drawing a circle." << std::endl;
    }
};

class Rectangle : public Shape {
public:
    void draw() const override {
        std::cout << "Drawing a rectangle." << std::endl;
    }
};

class Triangle : public Shape {
public:
    void draw() const override {
        std::cout << "Drawing a triangle." << std::endl;
    }
};

class Square : public Shape {
public:
    void draw() const override {
        std::cout << "Drawing a square." << std::endl;
    }
};

int main() {
    std::vector<std::unique_ptr<Shape>> shapes;
    shapes.emplace_back(std::make_unique<Circle>());
    shapes.emplace_back(std::make_unique<Rectangle>());
    shapes.emplace_back(std::make_unique<Triangle>());
    shapes.emplace_back(std::make_unique<Square>());

    for (const auto& shape : shapes) {
        shape->draw();
    }

    return 0;
}

这样使用智能指针 std::unique_ptr 可以自动管理对象的生命周期,避免手动释放内存可能带来的错误。