我有大约一年或两年的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)
AnimalCreation的目的是什么? 那和
之间的区别是什么typedef void(*AnimalCreation)();`//without asterisk after void
foo里面发生了什么?
如果foo接收到的期望参数始终是Animal的子类,为什么程序员需要像上面那样实现它而不仅仅是foo(Animal *)?
感谢。
答案 0 :(得分:2)
typedef void(*AnimalCreation)();
宣布&#34; AnimalCreation&#34;用作指向函数的类型别名,该函数不返回任何值,而这
typedef void*(*AnimalCreation)();
声明它被用作指向函数的指针的类型别名,该函数返回一个void指针,即一个你不知道它的类型的地址。
在foo
内,您正在接收这样一个&#34;通用地址&#34;并且您将 C-casting (可能不安全,在运行时检查)它转换为函数指针。这将由您自己承担风险:您不知道收到的地址指向的是什么。之后,您将调用该函数并接收另一个void指针,您将其重新解释为(危险的)Animal
个对象。然后你用它。
函数指针不能是任何子类,所以我不认为该代码中的参数是Animal子类...而 Animal类的子类是该函数返回的对象< / strong>即可。假设它也是一个多态类,那么您将能够使用虚拟继承规则调用其方法。如果您打算检查函数调用收到的指针,并且您不确定它是否是Animal
类的子类,那么您宁愿使用 dynamic_cast 。
作为旁注:在C ++中转换函数指针和void *是一种糟糕的做法,因为你丢失了有价值的类型信息。
答案 1 :(得分:2)
typedef行是AnimalCreation,被定义为function pointer type
函数foo接受一个void *参数,它将其转换为AnimalCreation类型(即进入函数指针类型)。然后它可以通过函数指针调用该函数。此调用返回void *(根据typedef - 在firts括号之前的部分是返回类型,因此为void *),然后通过reinterpret_cast将其转换为Animal *。
如果你从typdef中删除了星号 - 它仍会声明一个函数指针类型,但现在返回值将是void而不是void *(即没有返回,而不是指针)。您仍然可以通过函数指针调用该函数,但它不会返回任何内容。
总而言之,这是一个不错的小函数指针教程。
编辑:这段代码似乎在做什么的大局 - 这是在C ++中实现'工厂模式'的一种方式 - 抽象对象的创建,并将多态基类指针返回到派生类。在void *和函数指针之间进行转换以及reinterpret_cast不是实现这一目标的最好方法,对于你可以看到的替代方案here答案 2 :(得分:0)
首先,这是非常丑陋的C风格代码。
typedef void*(*AnimalCreation)();
要解释这一点,请遵循C&amp; C的一般规则。 C ++声明读取:如果您将声明类型化为表达式,您将获得其类型。
*AnimalCreation
这意味着AnimalCreation
是一个指针(*AnimalCreation)()
这意味着*AnimalCreation
是一个不带参数的函数,因此AnimalCreation
是一个不带参数的函数指针void *(*AnimalCreation)()
这意味着(*AnimalCreation)()
是void*
(=指向void
的指针),因此AnimalCreation
是指向不带参数的函数的指针返回void*
。如果它只是typedef void (*AnimalCreation)();
,它将是一个指向函数的指针,该函数不带参数并且不返回任何值(即返回void
)。
现在,foo()
。
它接受void*
(指向任何东西的指针)并将其解释为AnimalCreation
- 作为指向函数的指针,不带参数并返回void*
。如果传递给foo
的参数实际上属于那种类型,那么一切都很好。如果传入其他内容,程序将显示 Undefined Behavior,,这意味着任何事情都可能发生。例如,它很可能会崩溃,因为它可能试图将数据解释为代码。
foo()
调用传入的函数,返回void*
。 foo()
然后将其解释为指向Animal
的指针。如果那是函数实际返回的,那很好。如果没有,再次使用未定义的行为。
最后,您正在显示的调用将强制发生未定义行为,因为它正在传递指向对象的指针的地址。但是,如上所述,foo()
会将其解释为函数的地址,并尝试调用该函数。随之欢闹。
总而言之,这样的代码很糟糕,作者应该心疼。您期望看到这样的代码的唯一地方是与C风格的外部库的互操作性,在这种情况下,它应该非常好地记录。