【问题标题】:Void pointer pointer (void **)void 指针指针(void **)
【发布时间】:2014-05-30 07:03:34
【问题描述】:

我正在阅读http://msdn.microsoft.com/en-us/library/windows/desktop/dd389098(v=vs.85).aspx 的 COM 示例

我真的无法理解

中的(void **)
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);

所以我尝试了一些由类返回的不同类型指针的值

class Point{
private:
    int x, y;
public:
    Point(int inputX, int inputY){x = inputX, y = inputY;}
    int getX(){return x;}
    int getY(){return y;}
    friend ostream& operator << (ostream &out, Point &cPoint);
    Point operator-(){
        return Point(-x, -y);
    }
};

ostream& operator << (ostream &out, Point &cPoint){
    return out<< "(" << cPoint.x << ", " << cPoint.y << ")";
}

打印出来

Point *p = new Point(1,2);
cout << p << endl << &p << endl << endl
<< *&p << endl<< **&p << endl<<endl 
<< (void *) &p << endl << (void **) &p ;

(void*) 和 (void **) 确实没有区别。 (void **)&pControl 想要返回什么?

【问题讨论】:

  • void* 是指向某个未知数据类型的指针。 void** 有一个更具体的类型,它是一个指向void* 的指针,它们并不相同。除非pControlvoid*,否则这不是安全行为。如果是void*,就不需要演员了
  • 指针是特定于它们的类型,唯一的例外是void*,它只是“无类型”。但是指向(任意)指针的指针总是是专门类型的。在这种情况下,底层 decl void** 是一个指向空指针的指针。之所以需要强制转换,是因为 &amp;pControl evals 是指向特定类型的指针的地址(在您的情况下,是指向 pControl 的任何类型的指针的地址)。而void*可以保存任何data类型的地址;而 code 指针(指向函数的指针,成员或其他)是另一回事。
  • 不是任何类型,而是任何 data 类型。您不能(安全地)为void* 分配函数指针。 void* 是泛型在 C 中的实现方式,例如 qsort。在 C++ 中,我们有模板和多态性,所以它几乎不常见
  • "404 Page Not Found" 虽然......也许是这个? learncpp.com/cpp-tutorial/613-void-pointers
  • @HoyCheung 不,我只是弄乱了 url 语法,已编辑。

标签: c++ pointers com void-pointers pointer-to-pointer


【解决方案1】:
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);

(void **)&amp;pControl想要返回什么?

QueryInterface()IUnknown的三个方法之一,IUnknown所有 COM接口的基础根接口。

MSDN documentation for IUnknown::QueryInterface() 明确指出:

HRESULT QueryInterface(
  [in]   REFIID riid,
  [out]  void **ppvObject
);

ppvObject [out] 接收riid 参数中请求的接口指针的指针变量的地址。 成功返回后,*ppvObject 包含请求的接口指针,指向 目的。如果对象不支持该接口,则 *ppvObject 设置为 NULL

因此,在您的特定情况下,成功返回后,pControl 将包含指向IMediaControl 接口的请求指针,正如您在函数调用中通过第一个参数IID_IMediaControl 指定的那样。


现在,让我们尝试更好地理解为什么要使用双指针间接:void**

void* 表示“指向任何东西的指针”

所以,有人可能会想:“为什么QueryInterface() 的第二个参数不只是void*?”

问题是这个参数是一个输出参数。这意味着QueryInterface() 将在该参数中写入一些内容,供调用者使用。

而且,在 C 中(并且 COM 有几个 C-isms),当你有一个 输出 参数时,你必须使用一个 指针 (*)。 (注意在 C++ 中,您也可以使用引用 &amp;。)

因此,在这种情况下,我们有void* 的第一级间接寻址,这意味着“指向任何东西的指针”
第二级间接(另一个*),这意味着:“这是一个输出参数”

你也可以这样想:

typedef void* PointerToAnything;

HRESULT QueryInterface(..., /* [out] */ PointerToAnything* pSomeInterface);

// pSomeInterface is an output parameter.
//
// [out] --> use * (pointer), 
// so it's 'PointerToAnything*' (not just 'PointerToAnything'),
// so, with proper substitution, it's 'void**' (not just 'void*').

【讨论】:

  • 那么为什么要使用&pControl?我认为我们使用对象的方式是 pControl->function()。使用 &pControl,我们需要使用 (*pControl)->function(),这增加了更多的麻烦。
  • 在您的代码中,pControl 应该是指向某个 COM 接口的指针(例如 IMediaControl*)。但是当你传递给QueryInterface()时,你必须指定它的地址,即pControl地址,所以你使用&amp;pControl。那是因为QueryInterface() 的第二个参数是一个输出 参数。
  • 不,QueryInterface() 将某个 COM 接口的 地址 分配给指针。但要做到这一点,QueryInterface() 需要指针的地址(即pControl 的地址,即&amp;pControl)。
  • 我现在明白你的意思了。谢谢
猜你喜欢
  • 2013-12-18
  • 2020-04-01
  • 2021-07-22
  • 1970-01-01
  • 2019-09-27
  • 2014-05-13
  • 1970-01-01
  • 2016-11-23
  • 2016-03-21
相关资源
最近更新 更多