有没有合法的使用void *?
在C ++中是否有合法的void*
使用? 或者是因为C引入了它?
只想重述一下我的想法:
input :如果我们想要允许多种inputtypes,我们可以重载函数和方法,或者我们可以定义一个通用的基类或模板(谢谢你在答案中提到这一点)。 在这两种情况下,代码的描述性更强,而且错误更less(只要基类是以合理的方式实现的)。
输出 :我想不出任何情况下,我宁愿接受void*
,而不是从已知基类派生的东西。
只是为了明确我的意思:我没有具体询问void*
是否存在用例,但是如果有void*
是最好的或唯一可用的select。 下面几个人已经完全回答了。
void*
至less需要作为::operator new
(也是每个operator new
…)和malloc
并作为placement new
操作符的参数。
void*
可以被认为是每个指针types的常见超types。 所以它不完全是指向void
指针,而是指向任何东西。
顺便说一句,如果你想保留一些不相关的全局variables的数据,你可以使用一些std::map<void*,int> score;
然后,在声明全局int x;
和double y;
和std::string s;
做score[&x]=1;
和score[&y]=2;
和score[&z]=3;
memset
想要一个void*
地址(最通用的地址)
另外,POSIX系统有dlsym ,它的返回types显然应该是void*
使用void*
有多种原因,最常见的是3种:
- 在其接口中使用
void*
与C库进行交互 - types擦除
- 表示无types的内存
以相反的顺序,使用void*
(3)而不是char*
(或变体)来表示无types的内存有助于防止意外的指针运算; void*
上的操作很less,所以通常需要在执行前进行强制转换。 当然,就像char*
一样,没有锯齿的问题。
Type-erasure(2)仍然在C ++中与模板一起使用:
- 非generics代码有助于减less二元膨胀,即使在generics代码中,它在冷path中也是有用的
- 非generics代码有时候是需要存储的,即使在通用容器如
std::function
显然,当你处理的界面使用void*
(1)时,你没有多lessselect。
哦,是的。 即使在C ++中,有时我们也会使用void *
而不是template<class T*>
因为有时模板扩展的额外代码会过重。
通常我会使用它作为types的实际实现,并且模板types将从它inheritance并包装转换。
此外,自定义板分配器(运营商新的实现)必须使用void *
。 这是为什么g ++在void *
上添加了允许指针算术运算的扩展的原因之一,就像它的大小为1一样。
input:如果我们想允许多种inputtypes,我们可以重载函数和方法
真正。
或者我们可以定义一个通用的基类。
这是部分正确的:如果你不能定义一个通用的基类,接口或类似的东西,那该怎么办? 要定义那些你需要访问源代码的东西,这是不可能的。
你没有提到模板。 然而,模板不能帮助你的多态性:它们可以在编译时知道的静态types。
void*
可能被认为是最低的共同点。 在C ++中,你通常不需要它,因为(i)你不能固有地使用它,(ii)几乎总是有更好的解决scheme。
更进一步,你通常最终将其转换为其他具体types。 这就是为什么char *
通常更好,尽pipe它可能表明你期待一个C风格的string,而不是一个纯粹的数据块。 这就是为什么void*
比char*
更好的原因,因为它允许从其他指针types进行隐式转换。
你应该收到一些数据,使用它并产生一个输出; 要做到这一点,你需要知道你正在使用的数据,否则你有一个不同的问题,这不是你最初解决的问题。 例如,许多语言都没有void*
,并且没有任何问题。
另一个合法使用
当用printf
这样的printf
打印指针地址时,指针应该有void*
types,因此,你可能需要一个强制typesvoid
*
是的,它和其他语言一样有用。
作为一个例子,你可以使用它来擦除你需要的时候可以静态转换为正确types的类的types,以便获得一个最小和灵活的接口。
在这个回应中有一个应用的例子应该给你一个想法。
为了清楚起见,我复制并粘贴在下面:
class Dispatcher { Dispatcher() { } template<class C, void(C::*M)() = C::receive> static void invoke(void *instance) { (static_cast<C*>(instance)->*M)(); } public: template<class C, void(C::*M)() = &C::receive> static Dispatcher create(C *instance) { Dispatcher d; d.fn = &invoke<C, M>; d.instance = instance; return d; } void operator()() { (fn)(instance); } private: using Fn = void(*)(void *); Fn fn; void *instance; };
显然,这只是void*
的一堆用法之一。
与一个返回指针的外部库函数接口。 这是一个Ada应用程序。
extern "C" { void* ada_function();} void* m_status_ptr = ada_function();
这会返回一个指向Ada想告诉你的东西的指针。 你不需要做任何事情,你可以把它交给Ada来做下一件事。 事实上,在C ++中解开Ada指针并不重要。
简而言之,C ++作为一种严格的语言(不考虑像malloc()这样的C遗迹)需要void *,因为它没有所有可能types的公共父类。 与ObjC不同的是,例如,它有对象 。
我想到的第一件事(我怀疑是上面几个答案的一个具体例子)是能够将对象实例传递给Windows中的threadproc。
我有几个需要这样做的C ++类,它们有工作线程实现,并且CreateThread()API中的LPVOID参数获得了类中静态方法实现的地址,所以工作线程可以完成工作这个类的一个特定的实例。 在threadproc中简单的静态转换产生了实例来处理,允许每个实例化的对象有一个来自单个静态方法实现的工作者线程。
在多重inheritance的情况下,如果你需要获得一个指向一个对象占用的内存块的第一个字节的指针,你可以dynamic_cast
void*
。