void*
在C++中是否合法使用?或者这是因为C有它吗?
只是回顾一下我的想法:
输入:如果我们想要允许多个输入类型,我们可以重载函数和方法,或者我们可以定义一个公共基类或模板(感谢在答案中提到这一点).在这两种情况下,代码都更具描述性并且更不容易出错(假设基类以合理的方式实现).
输出:我想不出任何我希望接收的情况 void*
,而不是从已知基类派生的东西.
只是为了说明我的意思:我没有具体询问是否有用例void*
,但是如果有一个案例void*
是最好的或唯一可用的选择.以下几个人已经完全回答了这个问题.
void*
至少是必要的结果::operator new
(也是每个operator new
...)malloc
和作为放置new
运算符的参数.
void*
可以认为是每种指针类型的常见超类型.所以它并不完全是指向指针void
,而是指向任何东西的指针.
顺便说一句,如果你想保留一些数据了几个不相关的全局变量,你可能会使用一些std::map
话,在宣布全球之后int x;
和double y;
和std::string s;
做score[&x]=1;
与score[&y]=2;
和score[&z]=3;
memset
想要一个void*
地址(最通用的地址)
此外,POSIX系统有dlsym,其返回类型显然应该是void*
使用的原因有很多void*
,其中最常见的是:
使用void*
其界面与C库交互
类型擦除
表示未打字的内存
以相反的顺序,用void*
(3)代替char*
(或变体)表示非类型存储器有助于防止意外指针算术; 可用的操作非常少,void*
因此通常需要在有用之前进行铸造.当然,就像char*
没有别名问题一样.
Type-erasure(2)仍然在C++中使用,与模板一起使用或不使用:
非泛型代码有助于减少二进制膨胀,即使在通用代码中也可用于冷路径
有时候,非通用代码是存储所必需的,即使在通用容器中也是如此 std::function
显然,当您处理的界面使用void*
(1)时,您别无选择.
哦,是的.即使在C++中,有时我们也会使用,void *
而不是template
因为有时模板扩展中的额外代码会过重.
通常我会将它用作类型的实际实现,模板类型将从它继承并包装强制转换.
此外,自定义slab分配器(运算符新实现)必须使用void *
.这就是为什么g ++添加了允许指针算术的扩展的原因之一,void *
就好像它的大小为1.
输入:如果我们想要允许多种输入类型,我们可以重载函数和方法
真正.
或者我们可以定义一个公共基类.
这部分是正确的:如果你不能定义一个公共基类,接口或类似的东西怎么办?要定义您需要访问源代码的那些,这通常是不可能的.
你没有提到模板.但是,模板无法帮助您实现多态:它们使用静态类型,即在编译时已知.
void*
可以认为是最低的共同标准.在C++中,你通常不会需要它,因为(我),你可以不是天生做与它及(ii)几乎总有更好的解决方案.
更进一步,您通常会将其转换为其他具体类型.这就是为什么char *
通常会更好,虽然它可能表明你期待的是C风格的字符串,而不是纯粹的数据块.这就是为什么void*
比那更好的原因char*
,因为它允许从其他指针类型隐式转换.
你应该接收一些数据,使用它并产生输出; 要实现这一点,您需要知道您正在使用的数据,否则您遇到的问题与您最初解决的问题不同.例如,许多语言都没有void*
,也没有问题.
当使用像printf
指针这样的函数打印指针地址时应该有void*
类型,因此,您可能需要转换为void
*
是的,它与语言中的任何其他东西一样有用.
例如,您可以使用它来擦除您可以在需要时静态强制转换为正确类型的类的类型,以便具有最小且灵活的界面.
在那个回答中,有一个使用的例子可以给你一个想法.
为了清楚起见,我将其复制并粘贴在下面:
class Dispatcher { Dispatcher() { } templatestatic void invoke(void *instance) { (static_cast (instance)->*M)(); } public: template static Dispatcher create(C *instance) { Dispatcher d; d.fn = &invoke ; d.instance = instance; return d; } void operator()() { (fn)(instance); } private: using Fn = void(*)(void *); Fn fn; void *instance; };
显然,这只是众多用途中的一种void*
.