You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++如何确保子类重写函数时调用了基类的对应原函数

确保子类重写函数时必须调用基类对应函数的实现方案

有两种成熟的实现方向,分别对应运行时校验和编译期约束,可根据业务场景选择:


方案1:运行时校验方案

适合需要支持动态多态、多层继承的场景,未调用基类函数时会直接抛出异常或触发断言。
核心思路是基类内部维护调用标记,公共调用入口统一校验标记状态:

#include <iostream>
#include <stdexcept>

class Base
{
private:
    mutable bool base_func_called = false;
public:
    virtual void func()
    {
        base_func_called = true;
        std::cout << "Really important code was ran" << std::endl;
    }

    // 外部统一调用入口,代替直接调用func
    void call_func()
    {
        base_func_called = false;
        func();
        if (!base_func_called) {
            throw std::runtime_error("子类重写func时未调用Base::func");
        }
    }
};

class ChildExplicit : public Base
{
public:
    void func() override
    {
        Base::func(); // 调用后自动标记为已调用
        std::cout << "child class explicitly calling Base::func" << std::endl;
    }
};

class ChildImplicit : public Base
{
public:
    void func() override
    {
        // 未调用Base::func,调用call_func时会抛出异常
        std::cout << "child not explicitly calling Base::func" << std::endl;
    }
};

int main()
{
    try {
        Base* explicitChild = new ChildExplicit();
        explicitChild->call_func();
        std::cout << std::endl;

        Base* implicitChild = new ChildImplicit();
        implicitChild->call_func();
    } catch (const std::exception& e) {
        std::cout << "错误:" << e.what() << std::endl;
    }
    return 0;
}

如果需要多层继承每一层的实现都必须被调用,只需要每层维护自己的调用标记,在call_func中逐层校验即可。


方案2:改进版非虚拟接口(NVI)模式

适合对性能要求高、希望编译期就确保逻辑不会遗漏的场景,无运行时开销,多层继承场景下逻辑也不会混乱。
核心思路是把公共入口设为非虚函数,固定执行各层必走逻辑,子类只需要重写对应层级的扩展点:

#include <iostream>

class Base
{
public:
    // 非虚公共入口,固定执行基类必走逻辑
    void func()
    {
        std::cout << "Really important code was ran" << std::endl;
        do_base_extend();
    }
protected:
    // 基类的子类扩展点
    virtual void do_base_extend() = 0;
};

// 中间继承层
class MidLayer : public Base
{
protected:
    // 中间层的子类扩展点
    virtual void do_mid_extend() = 0;
private:
    // 重写基类扩展点,固定执行中间层必走逻辑
    void do_base_extend() override
    {
        std::cout << "中间层必走的代码逻辑" << std::endl;
        do_mid_extend();
    }
};

// 最终实现子类
class FinalChild : public MidLayer
{
protected:
    // 只需要重写当前层级的扩展点即可
    void do_mid_extend() override
    {
        std::cout << "最终子类的自定义逻辑" << std::endl;
    }
};

int main()
{
    Base* child = new FinalChild();
    child->func();
    // 输出顺序固定为:基类逻辑→中间层逻辑→子类逻辑,不会遗漏任何层级的必走代码
    return 0;
}

内容的提问来源于stack exchange,提问作者Gian Laager

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 09:15:04