2012-04-18 54 views
4

我有一个函数使用OpenGL绘制一个圆,我想传递一个包含x和y坐标以及半径的结构。问题是这个函数必须与3个不同的结构一起使用,所有结构都包含绘图函数不使用的坐标,半径和其他一些东西。C:为一个函数参数发送不同的结构

是否有某种方法只有一个参数为3个不同的结构(一次只发送一个参数)。

我希望我已经足够精确。 PS:函数必须是“抽象的”。

回答

3

是的,你可以使用一个原型是这样的:

void foo(char type, void *data); 

使用类型确定要使用的数据作为其结构的功能,你是好。

struct c *prepareStructC(void); 
//... 
struct c *toto = prepareStructC(); 
foo('c', toto); 
//... 
void foo(char type, void *data) 
{ 
    int x, y; 
    switch (type) 
    { 
    case 'c': 
     x = ((struct c*)data)->x; 
     y = ((struct c*)data)->y; 
     break; 
    //... 
    } 
    //... 
} 

第二种选择,如果你想避免一个开关/箱,并能够在事后添加更多的结构类型,没有演变FOO,您可以确保所有的结构开始提供必要的数据,总是以相同的顺序,相同的类型。这样,您就可以像在C++的“接口”,并使用类型的抽象形式:

struct abstract 
{ 
    int x; 
    int y; 
    int radius; 
} 

struct a 
{ 
    struct abstract abs; 
    //... other data ... 
} 
struct b 
{ 
    struct abstract abs; 
    //... other data ... 
} 
struct c 
{ 
    struct abstract abs; 
    //... other data ... 
} 

//Two choices : either you have: 
void foo(void *data) 
{ 
    int x,y,r; 
    x = ((struct abstract*)data)->x; 
    y = ((struct abstract*)data)->y; 
    r = ((struct abstract*)data)->radius; 
    //... 
} 

//OR Smarter way: 
void foo2(struct abstract *data) 
{ 
    int x,y,r; 
    x = data->x; 
    y = data->y; 
    r = data->radius; 
} 
//Calling foo2 with: 
struct a *sa = prepareStructA(); 
struct b *sb = prepareStructB(); 
struct c *sc = prepareStructC(); 
foo2(sa->abs); 
foo2(sb->abs); 
foo2(sc->abs); 

第二种方法的第二部分可以让你更多的灵活性,在亚型打破的具体信息,使你把abs部分放在struct a/b/c的任何地方,并且在结构单一目的的原则中更好(坐标和半径为其他东西并不总是最好的。)

+0

+1用更聪明的方式第二个选项:这正是OO是如何在C. – mouviciel 2012-04-18 15:45:38

+0

谢谢你们实现,我在一个结构包含一个struct的打算。 – DennisVDB 2012-04-18 16:55:04

1

仅当函数接受void*作为参数,然后您将void*投射到第在解引用它来访问其中的数据之前,在函数中使用正确的指针类型。

typedef enum 
{ 
    type1, type2, type3 
} datatype; 

void foo(void* data, datatype type) 
{ 
    switch(type) 
    { 
     case type1: 
     // do something with data by casting it to the proper type 
     break; 

     // ... other cases here 
    } 
} 

然而,这样做你会)需要通过另一种说法,表示正在铸造到void*传递之前的原始类型,和b)你放弃的类型系统,这是几乎没有一个好主意并应始终避免。

如果采取这种方法,高度建议创建调用函数(即取void*)内部之前采取正确的三个类型分别为“包装”的功能。使其成为严格的约定,从不直接调用void*函数;只调用包装器。以这种方式,你仍然有类型系统来帮助编译错误。

void bar1(someStruct* data) 
{ 
    foo((void*) data, type1); 
} 
void bar2(someOtherStruct* data) 
{ 
    foo((void*) data, type2); 
} 
void bar3(yetAnotherStruct* data) 
{ 
    foo((void*) data, type3); 
} 
+0

你是对的,枚举比一个普通的“char”更好,我的第一个方法更加肮脏^^“ – Eregrith 2012-04-18 15:42:29

+0

同意,但是你用一个相同的数据”签名“开始单独的结构是很好的一点,类型系统和(理论上)随着时间的推移对主要功能的更改较少。 – 2012-04-18 15:47:07

相关问题