为什么要转换为void指针?

时间:2017-06-09 20:44:53

标签: c++

我在this question中看到了以下代码:

class CFoo
{
   int a;
public:
   CFoo():a(1){}
   ~CFoo(){}
   getNum(){return a;}
};

void tfunc(void* data)
{
    CFoo* foo = static_cast<CFoo*>(data);
    std::cout << "Number: " << foo->getNum();
    delete foo;
}

int main()
{
   CFoo* foo = new CFoo;
   void* dt = static_cast<void*>(foo);
   tfunc(dt); // or tfunc(static_cast<void*>(food));

   return 0;
}

并开始想知道为什么要将指向类型的指针转​​换为指向void的指针而不是简单地将void指针指定为实际指针。就像在上面的代码中调用tfunc一样,他可以像tfunc(&foo)那样调用它,而不是像使用静态强制转换static_cast<void*>(foo);那样将指针转换为void指针的类型。 ?

2 个答案:

答案 0 :(得分:1)

你的问题的措辞有点令人困惑,你实际上并没有问为什么转换为void*,你问为什么使用显式转换而不是依赖隐式转换,即

tfunc(static_cast<void*>(food)); // explicit casting

VS

tfunc(food); // implicit casting

这个问题比投射到void*更普遍。不幸的是,C++允许相当数量的隐含危险铸件。例如。在singedunsigned之间,从更宽的整数或浮点到更窄的整数,转换为bool并转换为void*。所有这些转换都有可能默默地在代码中引入错误。 c++11通过不允许缩小新的统一初始化语法{},向正确的方向迈出了一小步,但由于向后兼容性,所有先前的隐式强制转换仍然是允许的。

这就是鼓励明确施法的原因。它有助于显示作者的意图。它表明转换是明确需要的,而不是默默地发生,可能没有作者的知识。同样非常重要的是,它有助于代码审查或在阅读代码时通过标记排序&#34;这里有演员。查看此代码&#34;

时请注意这一点

答案 1 :(得分:0)

从上面的例子中我不明白为什么函数tfunc的签名是void tfunc(void* data)而不是void tfunc(class CFoo* data)

无论如何,将指向任何类型T的指针转换为void *是有效的,稍后将这样的指针转换回T*是有效的。 T*的转换可能是隐式的,而从void*转换回T*则需要明确。因此,在您的示例中,tfunc(foo)相当于tfunc(static_cast<void*>(foo))tfunc(dt)

关于CFoo*void*的转换点,有一个标准转换(参见this c++ online draft standard):

  

4(1)标准转化是内置的隐式转化   含义。第4条列举了全套此类转换。

     

4.10指针转换(2)类型为“指向cv T的指针”的prvalue,其中T是对象类型,可以转换为类型的prvalue   “指向cv void的指针”。转换非空指针的结果   指向对象类型的指针的值指向“指向cv void的指针”   内存中与原始指针值相同的字节的地址。   ...

我更喜欢隐式转换而不是显式转换,因为(隐式)标准转换的内置含义完全符合要求。

函数签名中void*的用例可能是想要传递不相关类型的对象,并在函数内部决定它必须返回哪种类型。例如,假设一个函数处理不同响应类型的回调,并且每个响应类型可能传递不同的(类层次独立的)对象:

void someCallback(int responseType, void *context) {
  if(responseType == 1) {
    CFoo1* foo1 = static_cast<CFoo1*>(context);
    ...
  }
  else {
    CFoo2* foo2 = static_cast<CFoo2*>(context);
    ...
  }
}