在 QueryInterface() 实现中调用 AddRef() 的正确方法
Proper way of calling AddRef() inside QueryInterface() implementation
我发现了一些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; }
兴趣线是标有// ###
注释的线。
在IUnknown
static_cast
指针上调用AddRef()
真的有必要吗?还是只是无用的样板代码?
换句话说,一个简单的AddRef()
调用(即 this->AddRef()
)没事就好吗?如果没有,为什么?
当然,你通常只有一个 AddRef() 实现,所以你怎么称呼它并不重要。 请注意代码使用ppv
的方式可能是灵感,它是无类型的(void**),因此需要强制转换。 也许撕掉会让你以不同的方式做这件事。
主要原因是撕掉接口指针(例如,对于很少使用的接口)和可聚合对象(或多或少相当于 mixins)。
在这些情况下(撕下或要求聚合 IID 时的聚合器),ppv
不是指向同一引用计数C++对象的接口指针。 因此,如果您也想支持这些情况,则该代码是必需的。
通过调用 this->AddRef
,也许您可以获得一些简单性或类型安全性,但代价是不支持未由同一C++对象显式实现的接口。
PS:与大多数书籍和文档所说的相反,在我看来:
- 聚合更类似于使用混合,而不是继承或组合;
- 聚合实际上是(缓存的)撕裂接口指针的特殊情况,而不是组合的特殊情况。
这是我的想法:
- 当你继承时,
- 你通常有机会覆盖(虚拟)方法,由于直接方法调用,聚合不是这种情况;当你使用组合时,你可能必须包装入站对象,以免内部对象将其身份泄漏到给定对象(例如,内部对象可能会将自身传递给入站对象的某个方法), 而聚合也意味着通过在可聚合对象上拥有两组
IUnknown
方法来共享身份,因此根本没有这个特定的问题; - 撕下具有自己的生存期,而可聚合对象与外部对象共享其生存期。 否则,可以仅在需要时创建其中任何一个,尽管聚合器通常会在创建可聚合对象后立即创建它们。
返回的接口不必是实现QueryInterface
的类的基类。
相关文章:
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 使用std::函数映射对象方法
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- C++从另一个类访问公共静态向量的正确方法是什么
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 没有为自己的结构调用列表推回方法
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 在类定义之后定义一个私有方法
- 枚举环境变量的惯用C++14/C++17方法
- 在 QueryInterface() 实现中调用 AddRef() 的正确方法