关于void指针、类和类型转换
about void pointer, classes and casting
我有大约一两年的c++经验,但我的编码方式与我在Java中的编码方式相同(简单的oop东西)。现在我有一个我不理解的示例代码。(它很大,所以我试着把它缩短,我希望它对你们来说足够清晰)
//in .h file
typedef void*(*AnimalCreation)();
//in .cpp
void foo(void* p)
{
AnimalCreation ac = (AnimalCreation)p;
Animal* current_animal = reinterpret_cast<Animal*>(ac());
current_animal->init();
}
//somewhere in another class foo is called
Dog* dog = new Dog(); //Dog is a subclass of Animal
foo((void*)&dog)
动画创作的目的是什么?这和有什么区别
typedef void(*AnimalCreation)();`//without asterisk after void
foo内部发生了什么?
如果foo接收的预期参数总是Animal的子类,为什么程序员需要像上面那样实现它,而不仅仅是foo(Animal*)?
谢谢。
typedef void(*AnimalCreation)();
这声明"AnimalCreation"用作指向不返回任何值的函数的指针的类型别名,而这个
typedef void*(*AnimalCreation)();
声明它用作指向函数的指针的类型别名,该函数返回一个空指针,即指向您不知道其类型的对象的地址。
在foo
中,您收到这样一个"通用地址",并且C将其转换为函数指针(可能不安全,在运行时检查)。这是由你自己承担的风险:你不知道接收到的地址指向什么。然后你调用函数并接收另一个void指针,你将其重新解释为(危险的)Animal
对象。然后你用它。
函数指针不能是任何东西的子类,所以我不认为代码中的参数是Animal子类。。。相反Animal类的子类是该函数返回的对象。假设它也是一个多态类,那么您将能够使用虚拟继承规则调用它的方法。如果您打算检查函数调用接收到的指针,并且不确定它是否是Animal
类的子类,那么您宁愿使用dynamic_cast。
附带说明:函数指针和void*之间的转换是C++中的一种错误做法,因为您会丢失有价值的类型信息。
typedef行是AnimalCreation,它被定义为函数指针类型
函数foo接收一个void*参数,并将其转换为AnimalCreation类型(即函数指针类型)。然后,它可以通过函数指针调用函数。此调用返回一个void*(根据typedef,第一个括号之前的部分是返回类型,因此是void*),然后通过repret_cast将其强制转换为Animal*。
如果从typdef中删除星号,它仍然会声明一个函数指针类型,但现在返回值将是void而不是void*(即不返回任何内容,而不是指针)。您仍然可以通过函数指针调用函数,但它不会返回任何内容。
总而言之,这是一个很好的函数指针教程。
EDIT:这段代码似乎在做什么——这是在C++中实现"工厂模式"的一种方法——抽象对象的创建,并返回一个指向派生类的多态基类指针。在void*和函数指针之间进行转换并重新解释_cast并不是实现这一点的最佳方式,您可以在这里查看
首先,这是一个非常丑陋的C风格代码。
typedef void*(*AnimalCreation)();
为了解释这一点,遵循C&C++声明读取:如果您将声明键入为表达式,您将获得它的类型。
*AnimalCreation
这意味着AnimalCreation
是一个指针(*AnimalCreation)()
这意味着*AnimalCreation
是一个不带参数的函数,所以AnimalCreation
是一个指向不带参数函数的指针void *(*AnimalCreation)()
这意味着(*AnimalCreation)()
是void*
(=指向void
的指针),因此AnimalCreation
是指向不带参数并返回void*
的函数的指针
如果它只是typedef void (*AnimalCreation)();
,那么它将是一个指向不带参数也不返回值的函数的指针(即返回void
)。
现在,foo()
。
它获取一个void*
(指向任何东西的指针),并将其解释为AnimalCreation
——作为指向不带参数并返回void*
的函数的指针。如果传递给foo
的参数实际上是那种类型的,那么一切都很好。如果传入了其他内容,程序将显示未定义的行为,这意味着任何事情都可能发生。例如,它很可能会崩溃,因为它可能试图将数据解释为代码。
foo()
调用传入的函数,返回一个void*
。CCD_ 24随后将其解释为指向CCD_ 25的指针。如果这就是函数实际返回的结果,那就太好了。如果没有,则再次显示未定义的行为。
最后,您显示的调用将强制执行Undefined Behavior,因为它正在传递指向对象的指针的地址。但是,如上所述,foo()
会将其解释为函数的地址,并尝试调用该函数。随之而来的是欢声笑语。
总之,这样的代码很糟糕,它的作者应该感到很糟糕。您唯一希望看到此类代码的地方是与C风格外部库的互操作性,在这种情况下,它应该有非常好的文档记录
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 将可变参数模板类型转换为 void,预期')'之前
- 关于void指针、类和类型转换
- 类型转换时C++ (void *) 变量和 (void *&) 变量有什么区别
- 类型转换指向 int 的 void 指针时出错
- 如何将 void 指针类型转换为 int 指针,然后在其中存储 int
- 无法从 void* 类型转换(类名::)() 以键入 void*(*)(void*)
- 引用 void* 的隐式类型转换
- 类型转换并将 void 指针变量分配给 VC++ 中的整数变量
- C++类型转换:将指针从 void 指针转换为类指针
- 将void指针类型转换为int时出现分段错误
- 为什么c++中需要从void指针进行类型转换
- 是否有一种方法可以自动转换void指针的类型
- CUDA:__device__和__global__错误:在"无符号"/"void"之前预期的构造函数、析构函数或类型转换"
- 提取2个指针类型转换为(void*)
- 不能在类型转换为void *的对象上调用成员函数指针
- CUDA 错误:'void'之前的预期构造函数、析构函数或类型转换
- 重新解释不带类型标识符的强制转换void
- 为什么它会在 arduino uno 代码中将错误:预期的构造函数、析构函数或类型转换放在"void"之前?