MST

星途 面试题库

面试题:C++非虚函数在复杂继承体系中的行为及应用场景

考虑一个复杂的C++继承体系,有Base类,Derived1类继承自Base,Derived2类又继承自Derived1,且Base类中有一个非虚函数calculate()。假设在某些应用场景下,需要确保通过不同层次的指针(Base*、Derived1*、Derived2*)调用calculate()时,始终执行Base类中的版本,同时又要保证代码的可维护性和扩展性。请阐述你的设计思路,包括可能涉及到的技术手段(如访问控制、模板元编程等),并给出相应的代码示例。
26.9万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 访问控制:将 calculate 函数声明为 privateprotected,然后在 Base 类中提供一个 public 接口来间接调用 calculate 函数。这样,外部代码只能通过 Base 类提供的接口来调用 calculate,确保始终执行 Base 类中的版本。
  2. 避免函数重写:由于 calculate 是非虚函数,派生类无法重写它,这符合始终执行 Base 类版本的要求。
  3. 可维护性和扩展性:通过将核心计算逻辑封装在 calculate 中,并且提供统一的接口,有利于代码的维护和扩展。如果需要修改计算逻辑,只需要在 Base 类的 calculate 函数中修改即可。

代码示例

#include <iostream>

class Base {
private:
    // 核心计算逻辑
    void calculate() {
        std::cout << "Base::calculate()" << std::endl;
    }
public:
    // 提供给外部调用的接口
    void executeCalculate() {
        calculate();
    }
};

class Derived1 : public Base {
public:
    // 这里不能重写 calculate 函数,因为它是 private 的
    void doSomething() {
        executeCalculate();
    }
};

class Derived2 : public Derived1 {
public:
    // 同样不能重写 calculate 函数
    void doAnotherThing() {
        executeCalculate();
    }
};

int main() {
    Base* basePtr = new Base();
    Derived1* derived1Ptr = new Derived1();
    Derived2* derived2Ptr = new Derived2();

    basePtr->executeCalculate();
    derived1Ptr->executeCalculate();
    derived2Ptr->executeCalculate();

    delete basePtr;
    delete derived1Ptr;
    delete derived2Ptr;

    return 0;
}

在上述代码中:

  • Base 类的 calculate 函数是 private 的,外部无法直接调用。
  • executeCalculate 函数作为公共接口,调用 calculate 函数。
  • Derived1Derived2 类继承自 Base,但无法重写 calculate 函数,它们通过调用 executeCalculate 来执行 Base 类中的 calculate 逻辑。通过这种方式,无论使用 Base*Derived1* 还是 Derived2* 指针调用 executeCalculate,始终执行的是 Base 类中的 calculate 版本。