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

【effective c++】条款四十一:了解隐式接口和编译器多态

文章目录

  • C++中的"两大世界":面向对象与泛型编程
    • 特性对比
    • 详解两种接口与多态
      • 面向对象的世界:显式接口与运行时多态
      • 泛型编程的世界:隐式接口与编译时多态
    • 核心要点与演进

请记住:
1. classes 和 templates 都支持接口(interfaces)和多态(polymorphism)。
2. 对 classes 而言接口是显式的(explicit),以函数签名为中心。多态则是通过 virtual 函数发生于运行期。
3. 对 template 参数而言,接口是隐式的(implicit),奠基于有效表达式。多态则是通过 template 具现化和函数重载解析(function overloading resolution)发生于编译期。

C++中的"两大世界":面向对象与泛型编程

《Effective C++》第41条,揭示了C++中并存的"两大世界":一个是我们熟悉的面向对象世界(以类和继承为基础),另一个是功能强大的模板泛型编程世界。两者都支持接口和多态,但实现方式和理念截然不同。

特性对比

特性面向对象(类 / 显式接口与运行时多态)泛型编程(模板 / 隐式接口与编译时多态)
接口形式显式接口:通过函数签名明确定义,在头文件中可见隐式接口:由模板代码中对类型参数的有效表达式约束
多态时机运行时:通过虚函数表(vtable)动态绑定编译时:通过模板实例化和函数重载解析实现
核心关系“是一个”(is-a):基于继承层次“行为像”(behaves-like-a,鸭子类型):基于有效操作
错误检测编译时检查函数签名,运行时可能发生未定义行为编译时检查所有表达式有效性

详解两种接口与多态

面向对象的世界:显式接口与运行时多态

在这个世界里,接口是显式的。它明确规定了类有哪些成员函数(包括名称、参数类型、返回类型),通常可以在类的头文件定义中直接看到。

// 显式接口示例: 一个简单的抽象基类classDrawable{public:virtualvoiddraw()const=0;// 纯虚函数,显式定义了接口virtual~Drawable()=default;};

多态通过虚函数在运行时实现。当你使用基类的指针或引用调用一个虚函数时,具体调用哪个函数实现是由该指针或引用所指向的实际对象类型在运行时决定的。

Circle circle;Rectangle rect;Drawable*shape1=&circle;Drawable*shape2=▭shape1->draw();// 运行时决定调用 Circle::draw()shape2->draw();// 运行时决定调用 Rectangle::draw()

泛型编程的世界:隐式接口与编译时多态

在模板编程中,接口是隐式的。它并不要求类型 T 必须继承自某个特定基类,而只要求类型 T 的对象能进行模板代码中所用的所有操作。这种约束基于有效的表达式,也被称为"鸭子类型"——如果它走起路来像鸭子,叫起来像鸭子,那它就可以被当作鸭子。

// 隐式接口示例: 一个简单的模板函数template<typenameT>voiddrawObject(constT&obj){obj.draw();// 隐式接口: 要求类型 T 必须有一个可调用的 draw() 方法}

多态则通过模板实例化和函数重载解析在编译时完成。编译器会为每个用于实例化模板的具体类型生成一份对应的代码。调用哪个函数或使用哪个操作符,在编译时就根据类型确定下来了。

// 编译时多态示例: 模板实例化与函数重载Circle circle;Robot robot;// 假设Robot也有draw()方法,但与circle无继承关系drawObject(circle);// 编译器为 T=Circle 生成特定代码,调用 Circle::draw()drawObject(robot);// 编译器为 T=Robot 生成特定代码,调用 Robot::draw()

核心要点与演进

理解这两种范式区别的关键在于:

  • 显式接口关于类型,强调"你是什么,才能做什么"。
  • 隐式接口关于表达式,强调"你能做什么,就是什么"。

现代C++(特别是C++20)引入了概念,它能让你为模板参数必须满足的隐式接口约束赋予一个显式的名称,大大提升了代码的可读性和错误信息的友好度。

// C++20 概念让隐式接口更显式template<typenameT>conceptDrawable=requires(T obj){{obj.draw()}->std::same_as<void>;// 显式地要求有 draw 方法};template<Drawable T>// 使用概念,意图更清晰voidrender(constT&obj){obj.draw();}

这两种范式是C++强大的基石,理解它们能让你在面向对象设计和泛型编程之间做出更合适的选择。

http://www.jsqmd.com/news/463138/

相关文章:

  • OpenClaw 中文版 安装 | 部署 | 局域网访问 | 反向代理 (2026年3月9日)
  • 专业标书查重软件怎么选?20 位资深专家深度测评给出答案-火眼审阅实力领跑 - 资讯焦点
  • 社区AI心理智能设备2026排行榜:谁才是社区心理服务最优解? - 健成星云
  • 2026年四川防火板生产哪家靠谱?可靠稳定且服务完善 口碑好适配多场景 - 深度智识库
  • MATLAB分布式驱动电动汽车模型 分布式驱动电动车整车模型/四轮驱动电动车整车模型/轮毂电机...
  • 智慧铁路巡检图像数据集铁路数字化应用和铁路轨道分割识别 铁路道口数据集 铁路轨道标志图像识别深度学习YOLO格式+VOC格式数据集第10543期
  • 【大模型开发进阶】揭秘 LangChain 架构与 RAG 核心工作流:从理论到实战
  • 香港十大机构深度评:靠谱服务提升录取竞争​力 - 博客湾
  • 最近研究了下域名防封相关的技术,发现防红系统其实是个挺有意思的猫鼠游戏。今天咱们就撸起袖子直接干代码,先来个最基础的PHP防跳转方案
  • 虚拟电厂里的光热电站:一场关于优化调度的探索
  • 计及电动汽车灵活性的微网多时间尺度协调调度模型 摘要:构建了含有电动汽车参与的微网/虚拟电厂多...
  • Word2010调整其中的表格样式
  • 单相光伏并网系统仿真。 采用电导增量法实现最大功率跟踪。 boost升压斩波电路。 双闭环控制
  • 2026年全品类意面厂家排行 康力全形态布局适配全场景需求 - 资讯焦点
  • 2026天津G5申请:高通过率国际高中与牛剑升学路径解析 - 品牌2026
  • LAabview数据监控系统的数据库、报表与报警功能完善
  • 计算机毕业设计springboot基于Java的粮食收购站管理系统的设计与实现 基于SpringBoot框架的农产品收储信息化服务平台设计与实现 Java Web环境下粮食流通溯源与交易撮合管理系统构
  • IIC库函数的基础配置及SHT31 MLX90614
  • 贾子哲学体系(Kucius Philosophy):以东方智慧为根基的跨学科理论框架与AI时代的文明方案
  • 基于非Copula理论的股票投资组合预测:利用高斯定理预测股票亏损风险研究(Matlab代码实现)
  • 北京美国留学咨询中介哪家靠谱?2026最新推荐避坑指南! - 资讯焦点
  • Linux系统编程(十)--- 数据库Sqlite3
  • 进阶3 翻译42 单词35
  • 2026年主流品牌咨询公司竞争格局与全景解析 - 品牌推荐
  • 西门子1200plc与1500plc通用PID调节仿真程序及其视频解说教程
  • 论文AIGC率80%降至5%实测:DeepSeek+豆包+Gemini去AI味指令及工具横评
  • 国内优质消泡剂供应商排行榜 精准选型指南 - 优质品牌商家
  • 基于非完整约束RRT算法与混合控制协议的充满障碍物环境中分散式非完整约束系统的避碰控制器研究(Matlab代码实现)
  • 软件开发的“最后时刻”:当公司开始用 AI Agents 全权交付项目
  • 2026新加坡本科预科新路径:六力维多课程中心双校区与贝勒比斯全球教育认证项目深度解析 - 品牌2026