代码之家  ›  专栏  ›  技术社区  ›  sharptooth

将隐式转换用于向上转换而不是QueryInterface()对于多重继承合法吗?

  •  5
  • sharptooth  · 技术社区  · 14 年前

    假设我有一个实现两个或更多COM接口的类(与 here

    class CMyClass : public IInterface1, public IInterface2 { 
    };
    

    QueryInterface() 必须为同一接口的每个请求返回相同的指针(需要显式向上转换才能正确调整指针):

    if( iid == __uuidof( IUnknown ) ) { 
        *ppv = static_cast<IInterface1*>( this );
        //call Addref(), return S_OK 
    } else if( iid == __uuidof( IInterface1 ) ) {
        *ppv = static_cast<IInterface1*>( this );
        //call Addref(), return S_OK 
    } else if( iid == __uuidof( IInterface2 ) ) {
        *ppv = static_cast<IInterface2*>( this );
        //call Addref(), return S_OK 
    } else {
        *ppv = 0;
        return E_NOINTERFACE;
    }
    

    IUnknown 对象中的s-1是 IInterface1 另一个是基础 IInterface2 . 以及 they are in different subobjects .

    让我们假装我打过电话 查询接口() 对于 界面2 查询接口() IInterface2* 任何函数 IUnknown* 对于 我不知道* 会找回的。事实上如果这个函数调用 查询接口() 对于 我不知道

    这在COM方面合法吗?当我有一个指向多重继承对象的指针并且允许隐式向上投射时,我该如何处理这种情况?

    4 回复  |  直到 7 年前
        1
  •  3
  •   Hans Passant    14 年前

    对象 . 你的QI实现正确地做到了这一点。

    如果没有接口标识的保证,COM方法就不能假定它所传递的IUnknown指针与它在调用该指针上的QI时所检索的IUnknown指针相同。因此,如果需要证明对象同一性,那么就需要一个单独的QI。

        2
  •  2
  •   Community Tales Farias    7 年前

    作为 Hans 指出,你的执行 QueryInterface

    这是政府的责任 用户 要使用的COM对象的 查询接口 任何时候。原因正是为了防止出现您所指出的情况:将IInterface1*或IInterface2*指针转换为IUnknown*指针将产生不同的物理值。

    实施者 防止用户做错事。

    它是否会导致应用程序失败取决于应用程序 关于比较COM对象的标识。

    MSDN: The Rules of the Component Object Model

    对象标识。 要求 查询接口 任何 对于特定接口 我不知道 必须始终返回相同的物理 指针值。这将启用呼叫 任意两个接口并比较 结果以确定 对象(相同的COM对象标识)。

    Oleg 指出,对象标识的失败将产生相当有限的影响,因为COM接口成员的调用基本上不受影响—如果函数签名匹配,则每个虚拟表条目将指向相同的函数地址。

    所有COM智能指针实现都使用 查询接口 当强制转换到其他接口时,或者当当前接口可疑时。它们的比较运算符自动使用 QueryInterface(IID_IUnknown, ...) 在每个输入指针上,以获得可直接比较的物理IUnknown*指针。如果您选择在整个应用程序中使用原始指针,对象标识失败将开始影响应用程序。

    失败不会显化的一种特殊情况是类没有任何菱形继承。但是,隐式强制转换在COM中总是非法的,不管它是否使应用程序崩溃。

        3
  •  2
  •   Oleg    14 年前

    IInterface1 IInterface2 QueryInterface() 对于 界面1 . 只有一个声明,那个类 CMyClass 界面1 CMY类 是一组方法 界面1 界面1

    所以你在课堂上实现了 CMY类 查询接口() AddRef() Release() 方法。在 查询接口() 将指针强制转换为类的实例 CMY类 static_cast<IUnknown*> .

    更新

    好 啊。你说如果你投 界面1 IUnknown 如果你投 界面2 包含两个指针 (哪些地址 查询接口() , 发布() 在这两种情况下)您将看到两个指针具有相同的包含。所以我也是对的!

    在纯C中实现COM有很多很好的例子。在这种情况下,您需要定义一个静态结构,其中包含指向虚拟函数的指针,如 , AddRef() 发布() 查询接口() . 它再一次表明,只有返回的contain对COM很重要,而不是指针(返回的vtable不重要)。

    再说一句话。在一些评论中,您提到了有许多方法实现的可能性 查询接口() , AddRef() 发布() 接口是纯抽象类 如果定义一个实现某些接口的类,那么就没有典型的类继承。你只有 一个类,包含来自所有接口的所有函数的一个实现 . 如果在C++中这样做,编译器就用相应的指针创建并填充静态表,这些指针指向函数的唯一实现。 , AddRef() 发布() 以此类推,但所有vtables都指向相同的函数。

    __declspec(novtable) ATL_NO_VTABLE ,但这不是你问题的一部分。

        4
  •  0
  •   wqw    14 年前

    如果你有 interface IInterface1 : IDispatch interface IInterface2 : IDispatch QI 对于 IUnknown IInterface1 IInterface2

    但是。。。

    IDispatch 界面1 可以返回与 对于 分发接口 界面2

    所以答案是(再次) 我不知道