【问题标题】:c++ COM interface inheritancec++ COM接口继承
【发布时间】:2017-07-23 10:50:16
【问题描述】:

我想知道在 COM 应用程序中通过继承实现代码重用的最佳方法是什么。

问题

据我了解,C++ 的虚拟继承模型不能在 COM 环境中使用,因为它不是语言独立的。

在纯 C++ 中,类层次结构可能如下所示:

interface IBase {
    virtual void BaseMethod() = 0;
};

interface IDerived : virtual IBase {
    virtual void DerivedMethod() = 0;
};

class CBase : public virtual IBase {
public:
    virtual void BaseMethod() override { /* Do something */ }
};

class CDerived : public IDerived, public CBase {
public:
    virtual void DerivedMethod() override { /* Do something */ }
};

这会产生以下层次结构:

IDerivedCBase 都实际上继承自 IBase

由于虚拟继承在 COM 中不可用,因此类层次结构更倾向于如下所示:

interface IBase {
    virtual void BaseMethod() = 0;
};

interface IDerived : IBase {
    virtual void DerivedMethod() = 0;
};

class CBase : public IBase {
public:
    virtual void BaseMethod() override { /* Do something */ }
};

class CDerived : public IDerived, public CBase {
public:
    virtual void DerivedMethod() override { /* Do something */ }
};

这会产生以下层次结构:

乍一看,IBase 的歧义似乎有问题。这可以通过实现IUnknown::QueryInterface 方法轻松解决。

真正的问题是,CDerived如何从CBase继承IBase的实现方法,即CBase::BaseMethod

在虚拟继承的情况下,CBase::BaseMethod 可以通过显性继承,但如果没有虚拟继承,这不会发生:在CDerived 中,定义了方法CBase::IBase::BaseMethod,但没有定义方法IDerived::IBase::BaseMethod,导致在 CBase 类中仍然是抽象的,因此不适合实例化。

解决此问题的一种方法是再次覆盖 CDerived 中的方法 BaseMethod

class CDerived : public IDerived, public CBase {
public:
    virtual void BaseMethod() override { CBase::BaseMethod(); }
    virtual void DerivedMethod() override { /* Do something */ }
};

这对性能有影响吗?有没有更好的方法来实现我想要的? CDerived 中函数的重复覆盖不是破坏了继承的整个想法吗?

【问题讨论】:

  • 这个问题是基于一个非常错误的假设。 COM 通过只看到接口的客户端代码来实现语言独立性。该实现是完全不可见的。这允许你做任何你想做的事情来实现接口,实际上使用非虚拟多重继承是样板方法。对于所有已实现的接口,只有一个函数来实现 QueryInterface、AddRef、Release 正是您想要的。任何 COM 基础教程都会向您展示如何做到这一点。

标签: c++ inheritance interface com


【解决方案1】:

ATL 广泛使用如下技术:

template <typename Itf>
class IBaseImpl : public Itf {
public:
  void BaseMethod() override;
};

class CBase : public IBaseImpl<IBase> {};

class CDerived : public IBaseImpl<IDerived> {
public:
  void DerivedMethod() override;
};

现在你有了直线继承:IBase IDerived IBaseImpl<IDerived> CDerived。

【讨论】:

    猜你喜欢
    • 2010-12-24
    • 2020-09-09
    • 2022-01-10
    • 2011-03-24
    • 1970-01-01
    • 2023-03-14
    • 2015-04-02
    • 2011-07-31
    相关资源
    最近更新 更多