【问题标题】:Proper way of calling AddRef() inside QueryInterface() implementation在 QueryInterface() 实现中调用 AddRef() 的正确方法
【发布时间】:2015-01-05 10:23:00
【问题描述】:

我发现QueryInterface() 的一些实现模式如下:

// Inside some COM object implementation ...

virtual HRESULT __stdcall QueryInterface(REFIID riid, void **ppv)
{
    *ppv = /* Find interface ... */
    if (*ppv == nullptr)
        return E_NOINTERFACE;

    static_cast<IUnknown *>(*ppv)->AddRef();  // ###         
    return S_OK;
}

感兴趣的行是用// ### 注释标记的行。

真的有必要在IUnknownstatic_cast-指针上调用AddRef()吗?还是只是无用的样板代码?
换句话说,一个简单的AddRef() 调用(即this-&gt;AddRef())就可以了吗?如果不是,为什么?

【问题讨论】:

  • 如果 interface->AddRef 映射到 this->AddRef 那么我想你可以只使用this,但总是这样吗?
  • @500-InternalServerError: 假设上面的代码是一些 COM 对象实现的一部分,比如class CSomeComponent : public IInterface1, public IInterface2 { ... };。一个简单的AddRef(); 调用而不是static_cast&lt;IUnknown*&gt;(*ppv)-&gt;AddRef(); 调用会有什么问题?
  • 顺便说一句:在this MSDN article - 遵循前面提到的 AddRef 调用模式 - 它读取 "[...] AddRef 再次通过生成的接口指针调用以支持一些罕见但允许的类组合场景”。我想知道这些场景是什么以及 AddRef() “调用样式”的技术原因是什么......

标签: c++ windows com


【解决方案1】:

当然,你通常只有 一个 AddRef() 实现,所以不管你怎么称呼它。请注意代码使用ppv 的方式是可能的灵感来源,它是无类型的(void**),因此需要强制转换。也许撕掉会让你这样做。

【讨论】:

    【解决方案2】:

    主要原因是分离接口指针(例如用于很少使用的接口)和可聚合对象(或多或少相当于 COM 的 mixins)。

    在这些情况下(当被要求提供聚合 IID 时的分离或聚合器),ppv 不是指向同一个引用计数的 C++ 对象的接口指针。因此,如果您也想支持这些情况,那么该代码是必要的。

    通过调用this-&gt;AddRef,也许您可​​以获得一些简单性或类型安全性,但代价是不支持未由同一 C++ 对象显式实现的接口。


    P.S.:在我看来,与大多数书籍和文档所说的相反:

    1. 聚合更类似于使用 mixins,而不是继承或组合;
    2. 聚合实际上是(缓存的)分离接口指针的一种特殊情况,而不是组合的一种特殊情况。

    这是我的想法:

    1. 当你继承时,你通常有机会覆盖(虚拟)方法,而聚合则不是这种情况,因为直接调用方法;当您使用组合时,您可能必须包装入站对象,以免内部对象将其身份泄漏给给定对象(例如,内部对象可能会将自身传递给入站对象的某些方法),而聚合也意味着通过以下方式共享身份在可聚合对象上有两组IUnknown 的方法,因此根本没有这个特殊问题;
    2. 撕下有自己的生命周期,而可聚合对象与外部对象共享其生命周期。否则,可能只在需要时才创建其中的任何一个,尽管聚合器通常会在它们自己创建后立即创建可聚合对象。

    【讨论】:

      【解决方案3】:

      返回的接口不必是实现QueryInterface的类的基类。

      【讨论】:

      • 我不明白...你能详细说明一下吗?谢谢。为什么一个简单的AddRef() 调用会出错?
      猜你喜欢
      • 2011-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-13
      • 2018-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多