深入理解C++ 多态<三>(Polymorphism)模板方法模式

模板方法模式(Template Method Pattern) ,在 C++ 中常通过 非虚接口(NVI, Non-Virtual Interface) 惯用法来实现。

核心思想

  • 基类 定义一个非虚的公共成员函数 (如 process()),它内部按照固定顺序调用一系列虚函数 (通常是 protected)。

  • 派生类重写这些虚函数,提供具体实现。

  • 当通过派生类对象或基类指针/引用调用基类的非虚函数时,基类的代码被执行,但内部的虚函数调用会动态绑定到派生类的重写版本。

  • 效果:基类控制算法骨架,派生类填充细节,实现了"派生类调用基类函数,基类函数再反向多态调用派生类函数"。

详细解释

  1. 派生类调用基类函数 :例如 DerivedA a; a.process();,process() 是基类的非虚函数,所以直接调用 Base::process()。

  2. 基类函数多态调用派生类函数 :Base::process() 内部调用 step1() 和 step2(),它们被声明为 virtual。由于 this 指向的是 DerivedA 对象,虚函数表(vtable)指向 DerivedA 的重写版本,因此实际执行 DerivedA::step1() 和 DerivedA::step2()。

  3. 好处 :基类可以强制算法流程(如先 step1 再 step2),派生类无法改变流程,只能重写具体步骤。这符合"开闭原则"------对扩展开放(可新增派生类),对修改关闭(基类接口稳定)。

  4. 注意:在基类构造函数或析构函数中调用虚函数不会发生多态,因为此时派生类部分尚未初始化或已销毁,虚表指向基类。所以 NVI 通常用于普通成员函数

cpp 复制代码
#include <iostream>

class Base {
public:
    // 非虚公共接口,定义算法骨架
    void process() {
        std::cout << "Base::process() 开始\n";
        step1();  // 虚函数,多态调用
        step2();  // 虚函数,多态调用
        std::cout << "Base::process() 结束\n";
    }

    virtual ~Base() = default;

protected:
    // 虚函数,供派生类重写
    virtual void step1() {
        std::cout << "  Base::step1() 默认实现\n";
    }
    virtual void step2() {
        std::cout << "  Base::step2() 默认实现\n";
    }
};

class DerivedA : public Base {
protected:
    void step1() override {
        std::cout << "  DerivedA::step1() 实现\n";
    }
    void step2() override {
        std::cout << "  DerivedA::step2() 实现\n";
    }
};

class DerivedB : public Base {
protected:
    void step1() override {
        std::cout << "  DerivedB::step1() 实现\n";
    }
    // 不重写 step2,使用基类默认实现
};

int main() {
    DerivedA a;
    DerivedB b;

    std::cout << "调用 a.process():\n";
    a.process();  // 派生类对象调用基类非虚函数

    std::cout << "\n调用 b.process():\n";
    b.process();

    // 通过基类指针多态调用
    Base* p = &a;
    std::cout << "\n通过基类指针调用 p->process():\n";
    p->process();

    return 0;
}
相关推荐
xiaoye-duck17 小时前
《C++ 项目:手写大模型接入 SDK》DeepSeek接口设计(上):初始化和全量响应
开发语言·网络·c++·语言模型
fpcc17 小时前
跟我学c++中级篇—streambuf在glog中的应用分析
开发语言·c++
吾与谁归in17 小时前
C#脚本工具,支持智能提示自动补全(WPF + Roslyn + AvalonEdit)
开发语言·c#·wpf
码匠许师傅17 小时前
【C++三方组件】OpenCV:计算机视觉的事实标准
c++
昂好的day17 小时前
WPF 从零入门(上):WPF 是什么、XAML 语法、布局与样式全解
开发语言·c#·wpf
飞浪纪元[FWC–FE]17 小时前
Qt 构建排错实录:从 MSB 1009 到生成器选型
开发语言·数据库·qt
fly-iot17 小时前
【FDE知识库】(1):AI 编程时代开发语言选型分析,云使用go,企业用java,算法python,底层c
开发语言·人工智能·golang
云边有个稻草人17 小时前
Prometheus Pushgateway教程:离线任务指标上报、Shell与Python示例、远程访问
开发语言·python·prometheus
暴走约伯17 小时前
【VFX工具链源码拆解 01】总体架构:大型项目特效流程的程序化落地
开发语言·经验分享·3d·unity·架构·游戏引擎
C^h1 天前
c++ string
开发语言·c++