MST

星途 面试题库

面试题:C++ 构造函数、析构函数与继承、多态的深度结合

设计一个C++类继承体系,基类为`Shape`,有虚析构函数。派生类`Circle`和`Rectangle`继承自`Shape`。在每个类的构造函数中记录对象创建的顺序(可以使用一个静态变量和静态函数),在析构函数中记录对象销毁的顺序。同时,通过一个函数接收`Shape*`指针,对不同类型的派生类对象进行操作,展示构造和析构顺序的正确性,以及多态在这个过程中的体现。请完整实现这个继承体系及相关功能代码,并解释为什么要在基类使用虚析构函数。
44.7万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
#include <iostream>
#include <vector>

class Shape {
public:
    static int createOrder;
    static int destroyOrder;
    int myCreateOrder;
    int myDestroyOrder;
    Shape() {
        myCreateOrder = ++createOrder;
        std::cout << "Shape created, order: " << myCreateOrder << std::endl;
    }
    virtual ~Shape() {
        myDestroyOrder = ++destroyOrder;
        std::cout << "Shape destroyed, order: " << myDestroyOrder << std::endl;
    }
    virtual void draw() const = 0;
};
int Shape::createOrder = 0;
int Shape::destroyOrder = 0;

class Circle : public Shape {
public:
    Circle() {
        std::cout << "Circle created, order: " << myCreateOrder << std::endl;
    }
    ~Circle() {
        std::cout << "Circle destroyed, order: " << myDestroyOrder << std::endl;
    }
    void draw() const override {
        std::cout << "Drawing a Circle" << std::endl;
    }
};

class Rectangle : public Shape {
public:
    Rectangle() {
        std::cout << "Rectangle created, order: " << myCreateOrder << std::endl;
    }
    ~Rectangle() {
        std::cout << "Rectangle destroyed, order: " << myDestroyOrder << std::endl;
    }
    void draw() const override {
        std::cout << "Drawing a Rectangle" << std::endl;
    }
};

void operateOnShape(Shape* shape) {
    shape->draw();
}

int main() {
    std::vector<Shape*> shapes;
    shapes.push_back(new Circle());
    shapes.push_back(new Rectangle());

    for (Shape* shape : shapes) {
        operateOnShape(shape);
    }

    for (Shape* shape : shapes) {
        delete shape;
    }

    return 0;
}

为什么要在基类使用虚析构函数

  1. 防止内存泄漏:当通过基类指针删除派生类对象时,如果基类析构函数不是虚函数,那么只会调用基类的析构函数,派生类的析构函数不会被调用。这会导致派生类中分配的资源无法被释放,从而造成内存泄漏。例如在上述代码中,如果Shape的析构函数不是虚函数,delete shape时,只会调用Shape的析构函数,CircleRectangle的析构函数不会被调用。
  2. 实现多态析构:虚析构函数确保了在通过基类指针删除对象时,能够调用正确的(即派生类的)析构函数。这是多态性在析构过程中的体现,保证了对象的完整销毁,释放所有分配的资源。