我在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指针的类型。 ?
答案 0 :(得分:1)
你的问题的措辞有点令人困惑,你实际上并没有问为什么转换为void*
,你问为什么使用显式转换而不是依赖隐式转换,即
tfunc(static_cast<void*>(food)); // explicit casting
VS
tfunc(food); // implicit casting
这个问题比投射到void*
更普遍。不幸的是,C++
允许相当数量的隐含危险铸件。例如。在singed
和unsigned
之间,从更宽的整数或浮点到更窄的整数,转换为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);
...
}
}