深入理解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;
}
相关推荐
Han.miracle7 分钟前
MySQL InnoDB:MVCC、记录锁、间隙锁、二级索引MVCC底层原理
java·开发语言
.YM.Z15 分钟前
C++——【红黑树】原理详解:定义、性质、插入变色与旋转实现
开发语言·c++
leisoo80971 小时前
融资融券数据怎么查两融指标含义与杠杆观察方法 IG50免费开源股票数据API接口
开发语言·jvm·数据库·python·json
霸道流氓气质1 小时前
多Agent通信机制与协议设计完全指南:从FIPA-ACL到A2A/MCP的Java生产级实战
java·开发语言
无名猿1 小时前
constexpr 能力扩张:从 C++11 到 C++20 的编译期计算
c++·性能优化·现代c++·编译期
007张三丰1 小时前
C/C++ 内存管理详解:从内存分布到 new/delete 底层原理
java·c语言·c++·内存管理
weixin_419658311 小时前
CANoe 使用指南:从输出窗口到数据回放的完整实战教程
开发语言·功能测试·车载系统·自动化·汽车
当青春邂逅吉米多维奇1 小时前
C#图解教程(第5版) 同步方法
开发语言·c#
骇客野人1 小时前
Java BIO / NIO / AIO 完整详解 + 编程技巧
java·开发语言·nio