MST

星途 面试题库

面试题:C++多态在复杂继承体系中的应用及性能优化

假设有一个复杂的C++继承体系,包含多层继承和多个虚函数,在实现多态的过程中,如何进行性能优化?例如,如何减少虚函数表带来的开销,以及如何避免不必要的动态类型转换。请详细阐述你的思路,并给出相关代码片段示例。
30.1万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

减少虚函数表带来的开销

  1. 使用非虚接口(NVI)惯用法
    • 思路:通过一个非虚的公有成员函数来调用一个虚的私有成员函数。这样,公有接口保持稳定,而私有虚函数可以在子类中被重写。外部调用始终通过非虚函数,避免了直接调用虚函数的开销。
    • 代码示例
class Base {
public:
    void doWork() {
        // 这里可以添加一些通用的前置处理
        doWorkImpl();
        // 这里可以添加一些通用的后置处理
    }
private:
    virtual void doWorkImpl() {
        // 默认实现
        std::cout << "Base::doWorkImpl" << std::endl;
    }
};

class Derived : public Base {
private:
    void doWorkImpl() override {
        std::cout << "Derived::doWorkImpl" << std::endl;
    }
};
  1. 使用静态多态(模板)
    • 思路:利用模板在编译期确定类型,从而避免运行时虚函数表的开销。这在一些特定场景下,比如算法的实现对于不同类型有相同的逻辑时非常有用。
    • 代码示例
template <typename T>
class StaticPolymorphism {
public:
    void doWork() {
        T* derived = static_cast<T*>(this);
        derived->doWorkImpl();
    }
};

class StaticBase : public StaticPolymorphism<StaticBase> {
public:
    void doWorkImpl() {
        std::cout << "StaticBase::doWorkImpl" << std::endl;
    }
};

class StaticDerived : public StaticBase {
public:
    void doWorkImpl() {
        std::cout << "StaticDerived::doWorkImpl" << std::endl;
    }
};

避免不必要的动态类型转换

  1. 使用虚函数而不是类型转换
    • 思路:在设计良好的继承体系中,尽量通过虚函数实现不同类型对象的差异化行为,而不是通过dynamic_cast进行类型判断后执行不同逻辑。
    • 代码示例
class Shape {
public:
    virtual double area() const = 0;
};

class Circle : public Shape {
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    double area() const override {
        return 3.14159 * radius * radius;
    }
};

class Rectangle : public Shape {
private:
    double width;
    double height;
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    double area() const override {
        return width * height;
    }
};

// 正确做法,通过虚函数实现
void printArea(const Shape& shape) {
    std::cout << "Area: " << shape.area() << std::endl;
}
  1. 在必要时使用static_cast替代dynamic_cast
    • 思路:如果能在编译期确定类型转换的安全性,使用static_castdynamic_cast用于运行时类型检查,开销较大。
    • 代码示例
Shape* shape = new Circle(5);
Circle* circle = static_cast<Circle*>(shape);
// 如果能确保shape指向的是Circle对象,用static_cast更高效