当我在COM中开发时,我总是看到(void**)类型转换如下.
QueryInterface(/* [in] */ REFIID riid,/* [out] */ void** ppInterface)
Run Code Online (Sandbox Code Playgroud)
它的确切含义是什么?
恕我直言,它告诉编译器不要强制执行类型验证,因为在编译时客户端代码不知道ppInterface指向的类型.
谢谢~~~
我这样理解:
void*p表示 AnyType*p
void**pp 表示指向AnyType的指针*
如果void**pp表示"指向void*的指针",那么编译器在看到它时会做什么检查?
sta*_*ica 18
为什么COM使用的原因void**有QueryInterface是有点特殊.(见下文.)
通常, void**简单地表示指向void*,并且它可以用于输出参数,即.指示函数可以返回值的位置的参数.您的注释/* [out] */表示ppvInterface将写入指向的位置.
"为什么带有指针类型的参数可以用作输出参数?" , 你问?请记住,您可以使用指针变量更改两件事:
ptr = ...)*ptr = ...)指针按值传递给函数,即.该函数获取自己传递给它的原始指针的本地副本.这意味着您可以更改函数(1)中的指针参数,而不会影响原始指针,因为只修改了本地副本.但是,您可以更改指向对象(2),这将在函数外部可见,因为副本具有与原始指针相同的值,因此引用相同的对象.
现在,关于COM具体:
指向接口(由指定者riid)的指针将在引用的变量中返回ppvInterface.QueryInterface通过上述机制(2)实现这一点.
有void**,*需要一个机制(2); 另一个*反映了这样的事实:QueryInterface不返回新创建的对象(IUnknown),而是已经存在的对象:为了避免重复该对象,IUnknown*返回指向该对象()的指针.
如果你问为什么ppvInterface有类型void**而不是IUnknown**,这似乎更合理的类型安全性(因为所有接口必须来自IUnknown),然后阅读下面的参数取自Don Box 的书Essential COM,p.60(章节类型强制和IUnknown):
另一个与细节相关的细微
QueryInterface问题涉及其第二个参数,即类型void **.具有讽刺意味的是QueryInterface,COM类型系统的基础在C++中具有相当类型不安全的原型[...]Run Code Online (Sandbox Code Playgroud)IPug *pPug = 0; hr = punk->QueryInterface(IID_IPug, (void**)&pPug);不幸的是,以下内容对C++编译器来说同样正确:
Run Code Online (Sandbox Code Playgroud)IPug *pPug = 0; hr = punk->QueryInterface(IID_ICat, (void**)&pPug);这种更微妙的变化也可以正确编译:
Run Code Online (Sandbox Code Playgroud)IPug *pPug = 0; hr = punk->QueryInterface(IID_ICat, (void**)pPug);鉴于继承规则不适用于指针,这种替代定义
QueryInterface并不能解决问题:Run Code Online (Sandbox Code Playgroud)HRESULT QueryInterface(REFIID riid, IUnknown** ppv);同样的限制也适用于指针的引用.对于客户来说,以下替代定义可以更方便地使用:
Run Code Online (Sandbox Code Playgroud)HRESULT QueryInterface(const IID& riid, void* ppv);[...]不幸的是,这个解决方案并没有减少错误的数量,并且通过消除对转换的需要,删除了C++类型安全可能处于危险中的可视指示符.鉴于所需的语义
QueryInterface,微软选择的参数类型是合理的,如果不是类型安全或优雅.[...]
caf*_*caf 17
A void **是指向a的指针void *.这可以用于传递void *将用作输出参数的变量的地址- 例如:
void alloc_two(int n, void **a, void **b)
{
*a = malloc(n * 100);
*b = malloc(n * 200);
}
/* ... */
void *x;
void *y;
alloc_two(10, &x, &y);
Run Code Online (Sandbox Code Playgroud)
它只是一个指针void*.
例如:
Something* foo;
Bar((void**)&foo);
// now foo points to something meaningful
Run Code Online (Sandbox Code Playgroud)
编辑: C#中可能的实现.
struct Foo { }
static Foo foo = new Foo();
unsafe static void Main(string[] args)
{
Foo* foo;
Bar((void**)&foo);
}
static unsafe void Bar(void** v)
{
fixed (Foo* f = &foo)
{
*v = f;
}
}
Run Code Online (Sandbox Code Playgroud)