关于void指针,类和转换

时间:2014-02-28 12:19:52

标签: c++ casting void-pointers

我有大约一年或两年的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 *)?

感谢。

3 个答案:

答案 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 ++声明读取:如果您将声明类型化为表达式,您将获得其类型。

  1. *AnimalCreation这意味着AnimalCreation是一个指针
  2. (*AnimalCreation)()这意味着*AnimalCreation是一个不带参数的函数,因此AnimalCreation是一个不带参数的函数指针
  3. void *(*AnimalCreation)()这意味着(*AnimalCreation)()void*(=指向void的指针),因此AnimalCreation是指向不带参数的函数的指针返回void*
  4. 如果它只是typedef void (*AnimalCreation)();,它将是一个指向函数的指针,该函数不带参数并且不返回任何值(即返回void)。

    现在,foo()

    它接受void*(指向任何东西的指针)并将其解释为AnimalCreation - 作为指向函数的指针,不带参数并返回void*。如果传递给foo的参数实际上属于那种类型,那么一切都很好。如果传入其他内容,程序将显示 Undefined Behavior,,这意味着任何事情都可能发生。例如,它很可能会崩溃,因为它可能试图将数据解释为代码。

    foo()调用传入的函数,返回void*foo()然后将其解释为指向Animal的指针。如果那是函数实际返回的,那很好。如果没有,再次使用未定义的行为。

    最后,您正在显示的调用将强制发生未定义行为,因为它正在传递指向对象的指针的地址。但是,如上所述,foo()会将其解释为函数的地址,并尝试调用该函数。随之欢闹。

    总而言之,这样的代码很糟糕,作者应该心疼。您期望看到这样的代码的唯一地方是与C风格的外部库的互操作性,在这种情况下,它应该非常好地记录。