将 COM 接口转换为它继承的接口 [英] Casting COM interface to interface from which it inherits
问题描述
- 让我们有
I1
接口和I2
继承自I1
(struct I2 : public I1 {..}
> 在 c++ 符号中) - 让我们拥有指向
I2
接口的指针:I2* p2;
- 我们需要获取指向
I1
接口的指针.
- let we have
I1
interface andI2
inherited fromI1
(struct I2 : public I1 {..}
in c++ notation) - let we have pointer to
I2
interface:I2* p2;
- we need get pointer to
I1
interface.
问题:
是
I1* p1 = p2;
// use p1
在没有任何假设、实现细节等的情况下,语义总是有效的.我们不需要在这里调用 QueryInterface
(即 p2->QueryInterface(IID_PPV_ARGS(&p1)
)
always valid by semantic without any assumption, implementations details etc.
and we not need call QueryInterface
here (ie p2->QueryInterface(IID_PPV_ARGS(&p1)
)
(从 c++ 语法我们甚至不需要在 I1* p1 = p2;
中使用显式转换,在 c 中需要cast I1* p1 = (I1*)p2;
但这不是语言层问题)
(from c++ syntax we even not need use explicit cast in I1* p1 = p2;
here, in c need cast I1* p1 = (I1*)p2;
but this is not language layer question)
或者更具体的例子.假设某个函数需要指向 I1
接口的指针(void fn(I1*)
),但我们有指向 I2* p2
的指针.我们可以按原样调用/传递 fn(p2)
(根据 c++ 正式规则这是正确的 - 我们可以将指向派生类的指针传递给基指针)
or even more concrete example. say some function require pointer to I1
interface ( void fn(I1*)
), but we have pointer to I2* p2
.
can we call/pass fn(p2)
as is ( from c++ formal rules this is correct - we can pass pointer to derived class in place base pointer)
我认为是,这是显而易见的,但因为存在另一个意见 -我只是想听听争论
my opinion that yes, and this is obvious, but because exist another opinion - I just wonder to hear the arguments
那么为什么这个演员可以?
so why is this cast ok?
- 我们可以使用
p2
指针从I2
调用任何方法吗?是的 I1
的任何方法也是I2
的方法吗?是的,因为I2
继承自I1
- 从
1
和2
我们可以使用p2
调用I1
的任何方法指针
- we can call any method from
I2
by usingp2
pointer? yes - any method of
I1
was method ofI2
too ? yes, becauseI2
inherit fromI1
- from
1
and2
we can call any method ofI1
by usingp2
pointer
这就够了.这里根本没有任何假设.通过使用 p2
指针(没有任何二进制修改),我们可以调用 I1
接口的任何方法.因此,这也是指向 I1
接口的有效指针
and this is enough. here no any assumption at all.
by using p2
pointer as is (without any binary modification) we can call any methods of I1
interface.
as result this is valid pointer to I1
interface too
可能,然后说下
I1* p1 = p2; // p1 == p2 on binary level, because COM interface have single vtable pointer
p1->func(..);// let func is some method of I1 interface
p2->func(..);// will be the exactly same binary code as p1->func(..)
so p1->func(..)
当且仅当 p2->func(..)
正确时正确.但是 p2->func(..)
是正确的
so p1->func(..)
correct when and only when, p2->func(..)
is correct. but p2->func(..)
is correct
有人可以说这有什么问题吗?是否存在隐藏假设?是否可以提供错误的示例?
can somebody say what's wrong here? are exist hidden assumption? are possible provide example when this is wrong?
一些附加说明
注意#1:
请不要混淆 caste I2
到 I1
与 cast I1
到 I2
.这个转换是错误的,需要调用 QueryInterface
please not confuse caste I2
to I1
with cast I1
to I2
. this cast is wrong and require call to QueryInterface
I1* p1;
I2* p2;
p2 = static_cast<I2*>(p1); // wrong !!
p1->QueryInterface(IID_PPV_ARGS(&p2)) // ok
为什么?让存在接口 I3
也继承自 I1
,但 I3
不继承自 I2
和 I2
不是继承自 I3
并且某些对象同时实现了 I2
和 I3
(作为结果和 I1
)这意味着该对象包含最少 2 个不同的 vtable 指针 - 一个指向 I2
,一个指向 I3
当我们查询到I1
接口时,QueryInterface
可以返回
why? let exist interface I3
which is also inherit from I1
, but I3
not inherit from I2
and I2
not inherit from I3
and some object implement both I2
and I3
(as result and I1
)
this mean that object containing how minimum 2 different vtable pointers - one to I2
and one to I3
when we query to I1
interface, QueryInterface
can return
static_cast<I1*>(static_cast<I2*>(this)) // pointer to I1 via I2 vtable
但是可以返回
static_cast<I1*>(static_cast<I3*>(this)) // pointer to I1 via I3 vtable
如果 p1
指向 I2
vtable cast 可以,但是如果 p1
指向 I3
vtable - 会是错误的结果 - p1
在这种情况下不是指向 I2
的有效指针但再次 - 关于另一个转换的问题.所以这一切都与问题无关.
if p1
point I2
vtable cast will be ok, but if p1
point to I3
vtable - will be wrong result - p1
not valid pointer to I2
in this case
but again - question about another conversion. so all this unrelated to question.
注意#2
但是在 p2->QueryInterface(IID_PPV_ARGS(&p1))
之后我们可以得到另一个二进制指针 p1
( p1 != p2
> 在二进制级别)?
but after p2->QueryInterface(IID_PPV_ARGS(&p1))
we can got another binary pointer p1
( p1 != p2
on binary level) ?
是的,可以!与之前的注释相同 - 如果对象继承 I2
和 I3
(两者都继承自 I1
但不是相互继承)在 p2->QueryInterface(IID_PPV_ARGS(&p1))
调用的结果中可以返回或
yes, can! the same as in previous note - if object inherit I2
and I3
(both it inherit from I1
but not from each other)
in result of p2->QueryInterface(IID_PPV_ARGS(&p1))
call can be returned or
static_cast<I1*>(static_cast<I2*>(this)) // in this case will be p2 == p1
或
static_cast<I1*>(static_cast<I3*>(this)) // in this case will be p2 != p1
所以如果 QueryInterface
可以返回不同的二进制指针到 I1
(不等于原始的 p2
) - 哪个是正确的?这是关于 p1 = p2
;投错了吗?否.两个指针都正确,可以用于I1
接口的调用方法.
so if QueryInterface
can return different binary pointer to I1
(not equal to original p2
) - which one is correct? this say about p1 = p2
; cast wrong ?
no. the both pointers is correct and can be used for call methods of I1
interface.
很多人可能会说 - 等等,但这怎么可能?
many may be say here - wait, but how this can be?
如果我们打电话p1->func(..)
和 p2->func(..)
和 p1 != p2
func()
会用不同的指针调用,但只有一个可以正确?
if we call
p1->func(..)
and p2->func(..)
and p1 != p2
the func()
will be called with different pointers, but only one can be correct?
这里的错误 - 我们有 2 个不同的 func()
- 如果 p1 != p2
p1->func
可以是 != p2->func
func
这里不是具体的函数地址.但是这个地址取自 vtable 到 p1
或 p2
的那个点.因为p1 != p2
- 这里将使用不同 vtables,并且这个vtables 中不同 指针.在这个 vtables 之一中,adjustor thunk(可能在两者中)调整传入的p1
(或p2
)指针,然后跳转到real";func
实现
error here - that we have 2 different func()
- in case p1 != p2
the p1->func
can be != p2->func
func
here not concrete function address. but this address taken from vtable to which point p1
or p2
.
because p1 != p2
- here different vtables will be used and different pointers in this vtables.
how minimum in one of this vtables will be adjustor thunk (possible in both) which adjust incoming p1
(or p2
) pointer and then jump to "real" func
implementation
再次 - 两个指针(p1 = p2
和 p2->QueryInterface(IID_PPV_ARGS(&p1))
)正确在这里,两者都可以使用
so again - both pointers (p1 = p2
and p2->QueryInterface(IID_PPV_ARGS(&p1))
) is correct here and both can be used
注意#3:
请不要混淆实现一个或多个 com 接口的 COM Interface 和 object.来自 接口指针和接口
please not confuse COM Interface and object which implement one or more com interfaces. from Interface Pointers and Interfaces
接口实现的实例实际上是一个指向指向方法的指针数组 - 即引用的函数表到接口中指定的所有方法的实现.
An instance of an interface implementation is actually a pointer to an array of pointers to methods - that is, a function table that refers to an implementation of all of the methods specified in the interface.
我不问转换指针到对象,它实现(继承)接口指向这个接口的指针.我只询问接口指针转换.
i not ask about convert pointer to object which implement (inherit) interface to pointer to this interface. i ask only about interface pointer conversion.
来自 c/c++ 声明的接口 - 这是指针大小的对象 - 包含指向方法指针数组的单个指针
interface from c/c++ declaration - this is pointer size object - containing single pointer to array of pointers to methods
interface IXxx
{
CONST_VTBL struct IXxxVtbl *lpVtbl;
};
例如
class I3 : public I1, I2
{
// new methods
};
这里I3
不是接口,而是实现I1
和I2
接口的对象.
here I3
not interface, but object which implement I1
and I2
interfaces.
注意#4界面布局未知"- 这不是真的.界面的布局始终是已知的并明确定义的.对象的布局,其实现接口未知.但这是不同的事情 - 我不假设任何对象布局.再次为什么示例与
note#4 "layout of interface is unknown" - this is not true. layout of interface is always known and explicit defined. layout of object, which implement interface is unknown. but this is different things - i not assume any layout of object. again why example with
class I3 : public I1, I2
{
// new methods
};
错了.
这里的二进制指针指向 I3
无效指针到 I2
(需要调整)尽管 I3
继承自 <代码>I2.但是com接口不能这样定义.我说下一个如果com接口I2
继承自I1
接口——指向I2
的指针也总是指向I1
的有效指针. 这是来自 接口定义
here binary pointer to I3
not valid pointer to I2
(require adjustment) despite I3
inherit from I2
.
but com interface can not be such defined. i say next
if com interface I2
inherit from I1
interface - pointer to I2
is always valid pointer to I1
too. this is from interface definition
只能再重复一遍例子
I1* p1 = p2;
p1->func(..);
p2->func(..);
p1
将是与 p2
相同的二进制值 - 这是由于特定的接口定义.结果 p1->func(..);
和 p2->func(..);
产生相同的二进制代码.如果 p1->func(..);
会出错 - p2->func(..);
也会出错.但是 p2->func(..);
是正确的定义
p1
will be the same binary value as p2
here - this is due specific interfaces definitions. as result p1->func(..);
and p2->func(..);
produce the same binary code. if p1->func(..);
will be wrong - p2->func(..);
will be wrong too. but p2->func(..);
is correct by definiton
推荐答案
如果您有多重继承,这在 COM 对象中很常见,您不能只使用简单的重新解释转换 - 它并不总是有效,即使在只是 C++ 术语.
If you have multiple inheritance, which is quite common for COM objects, you can't just use simple reinterpret casting - it doesn't always work, even in just C++ terms.
考虑:
class I3 : public I1, I2
{
// new methods
};
如果您尝试在 I3 指针上调用 I1 方法,它可能会起作用.但是要调用 I2 方法,必须调整指针,使其具有与 I2 指针相同的布局.
If you try to call I1 methods on an I3 pointer, it will probably work. But to call I2 methods the pointer has to be adjusted so it will have the same layout as an I2 pointer.
这篇关于将 COM 接口转换为它继承的接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!