Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

about void pointer, classes and casting

I have c++ experience for about a year or two but I code the same way I code in Java (simple oop stuff). Now I have this sample code which I don't understand. (it's quite big so I tried to make it shorter, I hope it's clear enough for you guys)

//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) 

What is the purpose of AnimalCreation? And what's the difference between that and

typedef void(*AnimalCreation)();`//without asterisk after void

What's happening inside foo?

If the expected argument foo receives is always a subclass of Animal why does the programmer need to implement it like in the above and not just foo(Animal*)?

Thanks.


2 Answers

typedef void(*AnimalCreation)();

this declares "AnimalCreation" to be used as type-alias for a pointer to a function which doesn't return any value, while this

typedef void*(*AnimalCreation)();

declares it to be used as a type-alias for a pointer to a function which returns a void pointer, i.e. an address to something you don't know its type.

Inside foo you're receiving such a "generic address" and you're C-casting(potentially unsafe, checked at runtime) it to a function pointer. This is at your own risk: you don't know what that received address is pointing to. And after that you're calling the function and receiving another void pointer which you reinterpret (dangerous) as an Animal object. And then you use it.

A function pointer cannot be a subclass of anything so I don't think the argument in that code is an Animal subclass... rather the subclass to the Animal class is the object returned by that function. Assuming that is also a polymorphic class, you will then be able to call its methods with the virtual inheritance rules. If you intend to check the pointer received by the function call and you're unsure whether it is a subclass of the Animal class, you'd rather be using dynamic_cast.

As a sidenote: converting between function pointers and void* is a bad practice in C++ since you lose valuable type information.

like image 130
Marco A. Avatar answered Dec 08 '25 16:12

Marco A.


The typedef line is AnimalCreation being defined as a function pointer type

Function foo takes in a void * argument which it casts into an AnimalCreation type (i.e. into the function pointer type). It can then invoke the function via the function pointer. This invocation returns a void * (as per the typedef - the part before the firts bracket is the return type, hence void*) which is then casted to an Animal* by reinterpret_cast.

If you removed the asterisk from the typdef - it would still declare a function pointer type, but now the return value would be void instead of void * (i.e. nothing returned, rather than a pointer). You could still invoke the function via the function pointer, but it would not return anything.

All in all, this is a nice little function pointer tutorial.

EDIT : the big picture of what this code seems to be doing - this is one way of implementing a 'Factory Pattern' in C++ - abstracting the creation of an object, and returning a polymorphic base class pointer to a derived class. Casting between void * and function pointers and reinterpret_cast is not the nicest way to achieve this, for alternatives you could look here

like image 29
Graham Griffiths Avatar answered Dec 08 '25 15:12

Graham Griffiths



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!