文章目录

  • 二进制兼容
    • 什么是二进制兼容
    • 为什么会二进制不兼容
    • 什么情况会导致二进制不兼容
  • 隐藏子类——解决二进制兼容
  • 参考资料

二进制兼容

在 上一章 的结尾处提到了二进制兼容的概念,这里先说说二进制兼容的问题。

什么是二进制兼容

简单说,就是我的可执行程序调用你的动态库(so/dll),若动态库发生改动,我替换库文件后仍可以直接运行,这就是二进制兼容。若需要重新编译才能运行,就是二进制不兼容。

为什么会二进制不兼容

二进制不兼容的根本原因是 升级动态库导致内存模型发生了改变 。如原本类中有一个 int 属性 a,升级之后在 a 前面添加了一个 int 属性 b。升级后,类多占用了 4 个字节。如果调用着不重新编译,原来调用 a 的地方已经变成 b 了,自然就会出问题。增加接口也会造成这样的问题,此时必须重新编译链接可执行程序,以更新动态库在程序中的对象模型。

什么情况会导致二进制不兼容

简单来说,只要改变了对象的内存模型,就会导致二进制不兼容 。例如:

  • 增加虚函数或改变虚函数的声明顺序,这会导致虚函数表中的函数位置发生变化(在末尾增加是一种取巧行为,如果类被继承,也还是会出问题);
  • 增加非静态属性;
  • 调整非静态属性的声明顺序。

例如,对于第三个版本,略做一点修改:

class NetworkV3 {public:virtual int Send(const std::string str) = 0;virtual int Recv(std::string &str) = 0;// 创建和销毁函数static NetworkV3* New();static void Delete(NetworkV3 *net);
};

这里,我将 Send 和 Recv 的声明顺序颠倒一下,若不重新编译,调用时就会出问题。我是在 CentOS 上使用 g++ 9.3 编译了,此时虽然没有发生崩溃,但明显有调用错误,即原来调用 Send 的地方改为调用 Recv 了,若参数不一致,则直接没有调用。只有重新编译后,程序才能正常运行。

隐藏子类——解决二进制兼容

可以通过一个隐藏的子类和友元的方式来解决二进制兼容的问题,其实就是 上一章 中两个版本(版本二和版本三)的结合。具体代码如下:

// network.h
// 版本4
class NetworkV4 {public:int Send(const std::string str);int Recv(std::string &str);// 创建和销毁函数static NetworkV4* New();static void Delete(NetworkV4 *net);protected:NetworkV4();~NetworkV4();
};// network.cpp
// 版本4
class NetworkV4Impl : public NetworkV4
{// 友元,NetworkV4 中可以访问 NetworkV4Impl 的私有成员friend class NetworkV4;private:// NetworkV4 的成员变量std::string str_;
};NetworkV4::NetworkV4() {}
NetworkV4::~NetworkV4() {}int NetworkV4::Send(const std::string str) {NetworkV4Impl *impl = (NetworkV4Impl*)this;// TODO: 通过访问 impl 的成员变量,实现 NetworkV4::Sendimpl->str_ = str;std::cout << "NetworkV4::Send: " << impl->str_ << std::endl;return impl->str_.size();
}int NetworkV4::Recv(std::string &str) {NetworkV4Impl *impl = (NetworkV4Impl*)this;// TODO: 通过访问 impl 的成员变量,实现 NetworkV4::Recvimpl->str_ = "ok";str = impl->str_;std::cout << "NetworkV4::Recv: " << str << std::endl;return str.size();
}// 创建和销毁函数
NetworkV4* NetworkV4::New() {return (new NetworkV4Impl());
}
void NetworkV4::Delete(NetworkV4 *net) {delete (NetworkV4Impl*)net;
}

NetworkV4 的接口只有成员函数(非虚函数),无成员变量,但构造函数和析构函数必须定义为 protected,防止外部创建对象,要使用静态方法创建对象。

只是有一点看着比较奇怪,为啥 NetworkV4Impl 一定要继承 NetworkV4 ,不继承是否可以。很显然的可以的,但如果不继承,就需要定义一个 NetworkV4Impl 全局变量,用于在 NetworkV4 中调用,而这与 NetworkV2 的方法几乎是一致的(NetworkV2 中使用的是成员变量)。但使用全局变量就有悖于 C++ 封装的特性,之所以搞这么复杂,还是为了封装得好用一些。

个人觉得这一种方法过于复杂了一点,没有上一章中的两种方法直观,这里就权当做个参考吧。


参考资料

  1. C++接口工程实践:有哪些实现方法?
  2. C++二进制兼容

C++ IMPL 模式解析(下)相关推荐

  1. C++ IMPL 模式解析(上)

    文章目录 抛砖引玉 C++ IMPL 模式 完全隐藏成员变量 抛砖引玉 试想一个问题,如果有一套收发数据的网络接口,需要提供给其他同事或厂家使用,包含头文件和动态库,假设头文件如下: // 版本1 c ...

  2. [设计模式] IMPL 模式

    说明: 模块型代码中经常可以看到有一些类叫做 class Aimpl , 同时还会存在一个叫 class A的类,从名称上看 Aimpl 是 A 的 implement  . 实际上,A 往往是当前模 ...

  3. 【flink】Flink 1.12.2 源码浅析 : yarn-per-job模式解析 从脚本到主类

    1.概述 转载:Flink 1.12.2 源码浅析 : yarn-per-job模式解析 [一] 可以去看原文.这里是补充专栏.请看原文 2. 前言 主要针对yarn-per-job模式进行代码分析. ...

  4. android色彩模式,Android Q 色彩(颜色)模式解析(一)

    Android 色彩(颜色)模式解析(一) Android Q 在系统设置中提供了可设置的色彩模式,当然这功能很多厂商早就有了-,落后归落后,我们还是看看Android是怎么实现的! Android ...

  5. 【flink】Flink 1.12.2 源码浅析 : yarn-per-job模式解析 TaskMasger 启动

    1.概述 转载:Flink 1.12.2 源码浅析 : yarn-per-job模式解析 [四] 上一篇: [flink]Flink 1.12.2 源码浅析 : yarn-per-job模式解析 Jo ...

  6. 跨境电商独立站模式解析与机会分析?

    随着以Shopify为代表的快速建站工具的兴起,独立站的入门门槛大大降低.因此2019年可能会是独立站一个新的爆发之年.那么国内跨境电商独立站是如何发展演变的,到底有哪些模式?对于希望转型做独立站的平 ...

  7. 实体操盘手开发分销商城小程序商业模式解析

    今天董技叔要分享的分销模式是B2C新零售的一种,说起新零售分销商城系统开发这个模式已经是非常普片了,但模式千千万,每一家企业都可以拥有一套属于自己的分销模式来构建商业体系 ,分销模式在小程序里依旧是主 ...

  8. 4种常见分支模式解析及优劣对比 | 研发效能提升36计

    摘要:4 种常见分支模式解析及优劣对比.团队研发的本质并不是团队规模越大,研发的效率就越高.我们以为团队规模越大,研发效率就会越高,可以做越多的东西,但是我们发现团队规模大到一定程度,整个研发效率是会 ...

  9. 联想 n700 android,联想双模触控无线鼠标N700 双模式解析

    联想双模触控无线鼠标N700  双模式解析 底部开关特写 联想双模触控无线鼠标N700鼠标在底部,有一个模式切换开关,我们看到档位是三档,但是实际上这个模式开关只有两档.最左边的是蓝牙4.0配对模式, ...

最新文章

  1. 第39-43课 thinkphp5完成商品会员价格功能(后置勾子afterInsert)
  2. IOS-TextField控件详解
  3. mysql5.7.18压缩包下载_Windows安装MySQL5.7教程
  4. 【Node学习】—Express框架的安装
  5. 这不是我想要的Serverless
  6. QByteArray使用方法举例
  7. L2-010 排座位 (25 分)(并查集)
  8. 笔记本锁定计算机功能键,如何锁上笔记本键盘_怎样锁定笔记本键盘
  9. 安川机器人io对照表_安川机器人IO信号对照表.pdf
  10. 云计算系统典型物理架构
  11. 关键词云图,实现搜索功能
  12. 广州艺术博物院走进春睡画院旧址“云赏画”
  13. 模糊综合评价在实际问题中的应用(案例)
  14. 利用ajax实现excel报表导出(解决乱码问题)
  15. 去中心化存储项目终极指南 | Filecoin, Storj 和 PPIO 项目异同 (上)
  16. 全息投影的三种热门展示方式
  17. 比较好用的服务器和网站在线测速工具分享
  18. Galaxy S4 GT-I9500如何root 安卓5.0.1
  19. real time robust malicious traffic detection via frequency domain analysis记录一下
  20. Idea中使用maven打包出现Cleaning up unclosed ZipFile for archive?

热门文章

  1. 写给20岁---30岁男人的忠告
  2. python sorted原理_深入理解Python的sorted
  3. manjaro增加虚拟内存(linux通用)
  4. pyecharts绘制地铁图_Python数据分析:柱形图的绘制方法
  5. mysql是mpp数据库_mysql迁移mpp数据库Greenplum
  6. 互联网快讯:极米多款产品获消费者青睐;粉笔科技口碑护城河拓展至线下;网信部门工作督导组进驻豆瓣网
  7. java 格式化日期_Java的日期格式化常用方法
  8. ImageView 使用详解
  9. ESP8266-使用浏览器动态连接路由器
  10. 百度地图API浏览器端的使用