当前位置: 首页 > article >正文

Effective C++ 条款41:了解隐式接口和编译期多态

文章目录

    • 条款41:了解隐式接口和编译期多态
      • 示例 1:显式接口与运行期多态
      • 示例 2:隐式接口与编译期多态
      • 示例 3:运行期多态与编译期多态的对比
      • 结论

条款41:了解隐式接口和编译期多态

面向对象编程(OOP)和泛型编程(GP)在接口和多态的实现方式上存在显著差异:

  1. OOP(运行期多态)

    • 接口:显式定义,集中于函数签名。
    • 多态:通过 virtual 函数在运行时实现。
  2. GP(编译期多态)

    • 接口:隐式定义,基于可以在模板中使用的有效表达式。
    • 多态:通过模板实例化和函数重载解析在编译时实现。

示例 1:显式接口与运行期多态

显式接口 通过清晰的函数签名定义,运行期多态 则由虚函数表支持:

class Shape {
public:
    virtual void draw() const = 0; // 显式接口
    virtual ~Shape() = default;
};

class Circle : public Shape {
public:
    void draw() const override { // 运行期多态
        std::cout << "Drawing Circle" << std::endl;
    }
};

void render(const Shape& shape) {
    shape.draw(); // 多态调用
}

int main() {
    Circle c;
    render(c); // 调用 Circle 的 draw 实现
    return 0;
}

在这里,Shape 明确定义了接口,Circle 通过运行期多态提供其实现。


示例 2:隐式接口与编译期多态

模板参数的接口是隐式的,只要模板实例化时所需的操作是可用的,代码就可以编译通过。

template<typename T>
void render(const T& shape) {
    shape.draw(); // 隐式接口:假定 T 有成员函数 draw
}

class Square {
public:
    void draw() const {
        std::cout << "Drawing Square" << std::endl;
    }
};

int main() {
    Square s;
    render(s); // 编译期多态:实例化 render<Square>
    return 0;
}

此例中的模板 render 并未显式要求 T 必须拥有 draw 函数,但只要 T 提供了 draw,模板就能正常编译。


示例 3:运行期多态与编译期多态的对比

如果需要同时支持运行期和编译期多态,可以通过接口和模板结合实现:

class Drawable {
public:
    virtual void draw() const = 0; // 运行期多态接口
    virtual ~Drawable() = default;
};

template<typename T>
class DrawableWrapper : public Drawable {
public:
    explicit DrawableWrapper(T obj) : object(obj) {}

    void draw() const override { // 使用编译期多态
        object.draw();
    }

private:
    T object;
};

class Triangle {
public:
    void draw() const {
        std::cout << "Drawing Triangle" << std::endl;
    }
};

int main() {
    Triangle t;
    DrawableWrapper<Triangle> wrappedTriangle(t);
    wrappedTriangle.draw(); // 通过运行期接口调用编译期多态的实现
    return 0;
}

结论

  • 显式接口和运行期多态 适合需要动态行为变化的场景,但运行时开销较高。
  • 隐式接口和编译期多态 适合泛型编程,能在编译期优化性能,但接口定义隐晦,需要注意约束管理。
  • 在设计时应根据需求选择适合的多态实现方式,必要时将两者结合使用以平衡灵活性和效率。

http://www.kler.cn/a/460034.html

相关文章:

  • 【Vim Masterclass 笔记05】第 4 章:Vim 的帮助系统与同步练习
  • 算法——回溯模式
  • 大模型Weekly 03|OpenAI o3发布;DeepSeek-V3上线即开源!
  • 【C语言】可移植性陷阱与缺陷(三):整数的大小
  • AWS re:Invent 2024 - Dr. Werner Vogels 主题演讲
  • 深入剖析MySQL数据库架构:核心组件、存储引擎与优化策略(一)
  • mysql只恢复某个库或某个表
  • 算法环境安装GPU驱动、CUDA、cuDNN、Docker及NVIDIA Container Toolkit
  • node.js文件压缩包解析,反馈解析进度,解析后的文件字节正常
  • Ungoogled Chromium127编译指南 Linux篇 - 项目要求(二)
  • 华为,新华三,思科网络设备指令
  • 异步爬虫之aiohttp的使用
  • fetch请求代码
  • 大数据_HBase的列族属性配置
  • Kotlin 协程基础知识总结四 —— Flow
  • 基于PyQt5的UI界面开发——图像与视频的加载与显示
  • Java爬虫获取速卖通(AliExpress)商品详情
  • SpringAI从入门到熟练
  • Linux day 1203
  • 41.1 预聚合提速实战项目之需求分析和架构设计
  • C++通讯录管理系统
  • 9. 大数据集群(PySpark)+Hive+MySQL+PyEcharts+Flask:信用贷款风险分析与预测
  • DotnetSpider实现网络爬虫
  • 云轴科技ZStack获评OpenCloudOS社区2024年度优秀贡献单位
  • C++ 设计模式:门面模式(Facade Pattern)
  • 基于Ubuntu2404桌面版制作qcow2镜像