【问题标题】:When implementing several COM interfaces at once how do I upcast to IUnknown?当一次实现多个 COM 接口时,我如何向上转换到 IUnknown?
【发布时间】:2010-12-17 01:44:46
【问题描述】:

假设我的 COM 对象实现了两个或多个 COM 接口:

class CMyClass : public IPersistFile, public IPersistStream {
};

在实现 QueryInterface() 时,我需要能够返回一个 IUnknown* 指针。由于这两个基本接口都是从 IUnknown 派生的,因此我不能隐式向上转换 - 这样的向上转换将是模棱两可的。要明确地向上转换,我需要使用以下两种方式之一:

 if( iid == __uuidof( IUnknown ) ) {
     *ppv = static_cast<IPersistFile*>( this );
     static_cast<IPersistFile*>( this )->AddRef();
     return S_OK;
 }

 if( iid == __uuidof( IUnknown ) ) {
     *ppv = static_cast<IPersistStream*>( this );
     static_cast<IPersistStream*>( this )->AddRef();
     return S_OK;
 }

看起来唯一的要求是,每当对一个对象调用 QI() 时,它每次都返回相同的指针,如果我选择任何强制转换并坚持下去,我就满足了这个要求。

我应该选择哪种向上转型以及为什么?

【问题讨论】:

    标签: c++ windows visual-c++ com


    【解决方案1】:

    IUknown 未实现。您需要提供 IUnknown 的所有实现。因此,对于 QI IUknown,您返回 this 指针。

    AddRef、Release 和 QI 都由您实现,而不是在父接口上,所以您只需调用 addref 就没有问题,不需要强制转换。

    【讨论】:

    • 不,在 MI 场景中不允许,因为结果不是唯一的。每个接口,当 QI'd for IUnknown 必须返回相同的。
    • 嗯,自从我做 COM 以来已经很久了,但我不记得有你描述的这个问题。也许我做到了。我认为这无关紧要,因为如果将对象创建为 CMyClass 无论您实际拥有什么接口,例如 IPersistFile,QI 调用都会跳转到 CMyClass::QueryInterface ...
    【解决方案2】:

    通常,如果您想将具有多个 IUnknown 继承的对象强制转换为 IUnknown,您可以将其强制转换为它的接口之一,然后再强制转换为 IUnknown...

    【讨论】:

    • 好的,但是第一个演员选择哪个界面?
    • 没关系,如果我记得正确的话,IUnknown 在层次结构中只有一个实现。你走的路,无关紧要!
    • 就像 Mark Ransom 说的,只需选择一个约定或一个最不容易从对象中删除的接口......这就是微软的做法,但我不知道他们是否有一个约定。
    • @Mike:您采用的路径相关的,因为即使它们指向相同的函数,编译器也会生成多个vtable。返回的地址会不一样,试试看。微软对对象在内存中的布局方式有非常完整的描述,但我目前在网上找不到。
    • Ahhh vtables,我想念那些指针(我现在正在做 C#)。我不能对这个说“我忘了”,谢谢你指出来!不要为链接而烦恼,我有“COM and ATL 3”这本书可以参考..
    【解决方案3】:

    你使用哪个upcast并不重要,只是你总是使用同一个。我只是选择一个约定,例如总是返回在继承列表中声明的第一个。

    【讨论】:

      【解决方案4】:

      Mark Ransom 已经给出了正确的答案——任何人都可以,只要它是一致的——但选择第一个有一个小优势。由于布局规则,第一个界面的IUnknown* 将指向对象的开头。任何其他IUnknown* 将指向对象中其他地方的后续 vtable 指针。出于调试目的,了解对象在内存中的起始位置非常有用。

      【讨论】:

        猜你喜欢
        • 2015-10-13
        • 2011-03-03
        • 2011-02-26
        • 2013-06-10
        • 2023-01-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-27
        相关资源
        最近更新 更多