C++ 中的接口继承与实现继承
为这篇 blog 打腹稿的时候,觉得自己很贱,居然玩弄 C++ 起来了。还用了 template 这种很现代、很有品味的东西。写完后一定要检讨。
起因是昨天写的那篇关于 gc 的框架。里面用了虚继承和虚的析构函数。这会导致 ABI 不统一,就是这个原因,COM 就不用这些。
说起 COM ,我脑子里就浮现出各种条条框框。对用 COM 搭建起来的 Windows 这种巨无霸,那可真是高山仰止。套 dingdang 的 popo 签名:虽不能至,心向往之。
好吧,我琢磨了一下如何解决下面的问题,又不把虚继承啦,虚析构函数啦之类的暴露在接口中。
简单说,我有几个接口是一层层继承下来的,唤作 iA iB 。iA 是基类,iB 继承至 iA 。
然后,我写了一个 cA 类,实现了 iA 接口;接下来我希望再写一个 cB 类,实现 iB 接口。但是,iB 接口的基类 iA 部分,希望复用已经写好的 cA 类。我想这并不是一个过分的需求。正如当年手写 COM 组件时,我对手写那些 AddRef Release QueryInterface 深恶痛绝。
用虚继承可以简单的满足这个需求:
以下是代码片段: #define interface interface iA { virtual void foo() = 0; }; interface iB : virtual public iA { virtual void bar() = 0; }; class cA : virtual public iA { virtual void foo(); // etc... }; class cB : virtual cA , virtual public iB { virtual void bar(); // etc... }; |
每当我创建一个 cB 对象,并返回 iB 接口指针时,cB 对象内部的继承关系,可以用个简单的图表示如下:
以下是引用片段: iB +- cB | | + + iA +- cA |
但是,我们在公开的 iX 接口定义中,使用了虚继承。这在不同编译器上可能有一些差异。如果组件写好后,动态库想拿给别人用,无法预知别人用的编译器,就会有问题。
嗯,这可能是个伪命题。或许不需要解决。但感觉最近有点犯贱。那么下面就讨论一下:怎么不在接口定义中使用 virtual 继承,而达到同样的目的呢?
我的方法是用 template 做一个中间层,然后手工写一些转发代码:
以下是代码片段: #define interface struct interface iA { virtual void foo() = 0; }; interface iB : public iA { virtual void bar() = 0; }; class cA : public iA { public: virtual ~cA(); virtual void foo(); // etc... }; template< typename IF > class tA : cA , public IF { virtual void foo() { cA::foo(); } }; class cB : tA<iB> { virtual void bar(); // etc... }; |
这样,模板 tA 解决了多继承后,接口实现的转发问题。(因为手工转发了 foo 的调用)
既然要转发,为什么要用多继承而不用组合呢?因为我需要 ~cA 正确的发挥作用。比如在 cA::foo 中可以正确的 delete this 。
下一个问题:如果还有一个 iC 继承于 iB ,然后在实现 cC 的时候,想复用 cB ,同时不想写太多的 api 转发代码。怎么办?
我初步的想法是,把 tA 模板的实现都改成虚继承,然后做一个 tB 模板。转发 cB 扩展的几个 api 。然后让 cC 从 tA tB 虚继承出来。随手写了一个,但编译有点问题,不想深入研究了。弄出个模板虚拟多继承,绝对是蛋痛啊。
研究 C++ 果然是浪费生命。
建议继续学习:
- 在C++里写一个不能被继承的类 (阅读:5740)
- PHP面向对象编程的三大特性 (阅读:3326)
- 多重继承及虚继承中对象内存的分布 (阅读:3119)
- Linux 系统文件描述符继承带来的危害 (阅读:2778)
- 关于python和C++中子类继承父类数据的问题 (阅读:2665)
- Javascript继承机制的设计思想 (阅读:2507)
- JavaScript 函数、作用域和继承 (阅读:2235)
- 再论Javascript的类继承 (阅读:2108)
- Javascript继承-原型的陷阱 (阅读:2155)
- Javascript面向对象编程(二):继承 (阅读:1954)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:云风的 BLOG 来源: 云风的 BLOG
- 标签: 继承
- 发布时间:2010-02-23 22:09:41
- [65] Oracle MTS模式下 进程地址与会话信
- [64] Go Reflect 性能
- [64] 如何拿下简短的域名
- [59] IOS安全–浅谈关于IOS加固的几种方法
- [58] 【社会化设计】自我(self)部分――欢迎区
- [58] 图书馆的世界纪录
- [56] android 开发入门
- [53] 视觉调整-设计师 vs. 逻辑
- [46] 读书笔记-壹百度:百度十年千倍的29条法则
- [45] 界面设计速成