1

I have read the book Understanding and Using C Pointers and try to compile the code below. But after compiling I got the warning: assignment from incompatible pointer type.

I have checked the code and find out the function pointer fptrSet and function ShapeSetX is incompatible because the first argument of fptrSet is void * and function ShapeSetX is Shape *.

How can I fix this? Thanks!

typedef void (*fptrSet)(void*, int);
typedef int  (*fptrGet)(void*);
typedef void (*fptrDisplay)();    

typedef struct _vfunc
{
    fptrSet     setX;
    fptrGet     getX;
    fptrSet     setY;
    fptrGet     getY;
    fptrDisplay display;    
} vFunc;    

typedef struct _shape
{
    vFunc function;
    int x;
    int y;
} Shape;

void displayShape(){
    printf("Shape\n");
}
void ShapeSetX(Shape *shape, int x){
    shape->x = x;
}
void ShapeSetY(Shape *shape, int y){
    shape->y = y;
}
int ShapeGetX(Shape *shape){
    return shape->x;
}
int ShapeGetY(Shape *shape){
    return shape->y;
}    

Shape *newShape()
{
    Shape *shape = (Shape *)malloc(sizeof(Shape));
    shape->x = 10;
    shape->y = 10;
    shape->function.setX = ShapeSetX;
    shape->function.getX = ShapeGetX;
    shape->function.setY = ShapeSetY;
    shape->function.getY = ShapeGetY;
    shape->function.display = displayShape;
    return shape;
}
FatMouse
  • 13
  • 4
  • I think you can also change the `typedef void (*fptrSet)(void*, int)` to `typedef void (*fptrSet)(Shape*, int)` and the same for `fptrGet`. – wake-0 Jun 14 '16 at 10:49
  • @KevinWallis I think he wants something like virtual table from C++, so because there are no inheritance in C, he has to use `void` to allow "derived" struct from `Shape` – Garf365 Jun 14 '16 at 10:51
  • @KevinWallis @Garf365 is right, as you see this code is try to simulate the vtable from C++, so the the argument must be `void *` – FatMouse Jun 15 '16 at 03:33
  • Also : take a look at http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc – Garf365 Jun 15 '16 at 07:16

2 Answers2

1

You have to respect pointer definition: pointer need that first parameter is a pointer to void, so your function implementation should have first parameter as void:

void ShapeSetX(void *void_shape, int x){
    Shape *shape = (Shape*) void_shape;
    shape->x = x;
}
void ShapeSetY(void *void_shape, int y){
    Shape *shape = (Shape*) void_shape;
    shape->y = y;
}
int ShapeGetX(void *void_shape){
    Shape *shape = (Shape*) void_shape;
    return shape->x;
}
int ShapeGetY(void *void_shape){
    Shape *shape = (Shape*) void_shape;
    return shape->y;
} 
Garf365
  • 3,619
  • 5
  • 29
  • 41
  • @Garf365 Thanks for you answer and you got what I want. I try to use the code to simulate the 'ploymorphism' from OOP. Really thank you ! – FatMouse Jun 15 '16 at 03:43
  • @FatMouse I think you have also to pass by a base structure, common on each instance (to access safetly to vtable). And also, in C++, vtable are static, you only store pointer to vtable in your instance. I try something to implements vtable here : http://ideone.com/P8dk6g any comments will be appreciate ;) – Garf365 Jun 15 '16 at 08:03
1

I was going to say "Why don't you replace void with Shape then?", until I realised that Shape hadn't been defined yet - nor could you swap the two definitions, because Shape needs vFunc which needs the typedefs.

So, do this:

typedef struct _shape Shape; // Define _shape and Shape later

typedef void (*fptrSet)(Shape*, int);
typedef int  (*fptrGet)(Shape*);
typedef void (*fptrDisplay)();    

If your compiler doesn't like that, you may need to change it to:

typedef struct _shape; // Define _shape later

typedef void (*fptrSet)(struct _shape*, int);
typedef int  (*fptrGet)(struct _shape*);
typedef void (*fptrDisplay)();    
John Burger
  • 3,662
  • 1
  • 13
  • 23
  • With this solution, you can use `_vfunc` with other structure than `Shape`. I think OP wants a solution to have "inheritance" solution in C – Garf365 Jun 14 '16 at 10:55
  • For example with a function `int getXOfInstance(void * instance, vFunc * vfunc) { return vfund->getX(instance);}` – Garf365 Jun 14 '16 at 10:57
  • @Garf I thought of that - but with names like `set/get' 'X/y` and `Display` it all sounded rather "Shape-y" – John Burger Jun 14 '16 at 11:00
  • It's not necessarily a Shape, it can be anything which have X, Y properties – Garf365 Jun 14 '16 at 11:01