【发布时间】:2014-12-14 23:27:29
【问题描述】:
我有一个使用 OpenGL 绘制圆的函数,我想向它传递一个包含 x 和 y 坐标以及半径的结构。问题是同一个函数必须与 3 个不同的结构一起使用,它们都包含坐标、半径和绘图函数不使用的其他一些东西。
有没有办法让 3 个不同的结构只有一个参数(一次只发送一个)。
我希望我已经足够精确了。
PS : 函数必须是“抽象的”。
【问题讨论】:
标签: c function structure abstract arguments
我有一个使用 OpenGL 绘制圆的函数,我想向它传递一个包含 x 和 y 坐标以及半径的结构。问题是同一个函数必须与 3 个不同的结构一起使用,它们都包含坐标、半径和绘图函数不使用的其他一些东西。
有没有办法让 3 个不同的结构只有一个参数(一次只发送一个)。
我希望我已经足够精确了。
PS : 函数必须是“抽象的”。
【问题讨论】:
标签: c function structure abstract arguments
是的,您可以使用这样的原型:
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中的任何位置,并且在a的原理上更好结构的单一用途(在结构内拥有坐标和半径和其他东西并不总是最好的。)
【讨论】:
仅当函数接受 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
}
}
但是,通过这样做,您将 a) 需要传递另一个参数,该参数表明原始类型在被传递之前被强制转换为 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);
}
【讨论】: