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

C++中子类调用父类重载方法:如何让父类foo触发子类doFoo且无开销?

解决方案:使用CRTP(奇异递归模板模式)实现静态多态

要让c.foo()调用Child::doFoo(),核心问题是父类Parent的foo()函数在编译时就静态绑定到了自身的doFoo(),而非子类的版本。由于C++不允许虚模板函数(template和virtual不能同时使用),我们可以用CRTP来实现无额外运行时开销的静态多态,具体修改如下:

#include <iostream>
#include <utility>

// 先声明子类,供父类模板使用
struct Child;

template<typename Derived>
struct Parent {
    template<class... Args>
    void doFoo(Args&&... args) {
        std::cout << "parent doFoo";
    }

    template<class... Args>
    void foo(Args&&... args) {
        // 通过静态转换将this转为子类指针,调用子类的doFoo
        static_cast<Derived*>(this)->doFoo(std::forward<Args>(args)...);
    }
};

struct Child : Parent<Child> {
    template<class... Args>
    void doFoo(Args&&... args) {
        std::cout << "child doFoo";
    }
};

int main() {
    Child c;
    c.foo(); // 输出:child doFoo
    return 0;
}

为什么这个方法有效?

  • 无额外开销:static_cast<Derived*>(this)是编译时完成的转换,完全没有运行时成本(比如虚函数表的查找开销)。
  • 精准调用子类实现:通过显式转换到子类指针,编译器会优先在子类作用域中查找doFoo(),自然调用子类的重写版本。
  • 保留模板灵活性:原有的模板参数包Args&&...和完美转发std::forward<Args>(args)...都被完整保留,不会损失函数的通用性。

原代码失效的原因

原代码中,Parent::foo()里的doFoo(args...)会在Parent的作用域中查找函数名,直接绑定到Parent::doFoo()。由于doFoo不是虚函数,即使子类重写了同名函数,也不会触发动态绑定——C++的非虚函数调用是编译时确定的,只看当前代码所在的类作用域,和对象的实际类型无关。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:27:02