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++ 果然是浪费生命。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++,类接口通常使用抽象类和纯虚函数来实现。抽象类是一种不能直接实例化的类,只能作为基类来派生出其他具体的子类。抽象类的纯虚函数没有具体的实现,只有函数声明,它们必须在派生类进行实现。这样,抽象类就定义了一组公共的接口,可以被具体的子类所继承实现。 以下是一个简单的抽象类的例子: ``` class Shape { public: virtual double area() const = 0; virtual void draw() const = 0; }; ``` 这里定义了一个Shape抽象类,包括两个纯虚函数area和draw。这个类不能被直接实例化,只能被用来派生出具体的形状类,比如Rectangle和Circle。这些具体的形状类必须实现Shape类的纯虚函数,才能被实例化。 多态是C++的一个重要特性,它允许在运行时根据对象的实际类型来调用相应的方法。在C++,多态通常通过虚函数和指针或引用来实现。 以下是一个简单的多态的例子: ``` void printArea(const Shape& shape) { cout << "Area: " << shape.area() << endl; } int main() { Rectangle rect(3, 4); Circle circle(5); printArea(rect); printArea(circle); return 0; } ``` 这里定义了一个printArea函数,它接受一个Shape类型的引用作为参数。在main函数,创建了一个Rectangle对象和一个Circle对象,并分别传递给printArea函数。由于Shape类的area函数是虚函数,所以在运行时会根据对象的实际类型来调用相应的area函数,从而实现多态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值