我对 C 编程并不陌生。但我不明白为什么在 C 中将函数指针保留为结构成员很有用。示例:
// Fist Way: To keep pointer to function in struct
struct newtype{
int a;
char c;
int (*f)(struct newtype*);
} var;
int fun(struct newtype* v){
return v->a;
}
// Second way: Simple
struct newtype2{
int a;
char c;
} var2;
int fun2(struct newtype2* v){
return v->a;
}
int main(){
// Fist: Require two steps
var.f=fun;
var.f(&var);
//Second : simple to call
fun2(&var2);
}
程序员是否使用它来为他们的 C 代码提供面向对象 (OO) 的形状并提供抽象对象,或者只是让代码看起来技术性强?
我认为在上面的代码中,第二种方式更加温和,也非常简单。在第一种方式中,我们仍然必须传递
&var
,即使 fun()
是结构体的成员。
如果将函数指针保留在结构体定义中是好的,请解释原因。
提供结构体上函数的指针可以让您动态选择对结构体执行哪个函数。
struct newtype{
int a;
int b;
char c;
int (*f)(struct newtype*);
} var;
int fun1(struct newtype* v){
return v->a;
}
int fun2(struct newtype* v){
return v->b;
}
void usevar(struct newtype* v) {
// at this step, you have no idea of which function will be called
var.f(&var);
}
int main(){
if (/* some test to define what function you want)*/)
var.f=fun1;
else
var.f=fun2;
usevar(var);
}
这使您能够拥有单个调用接口,但根据您的测试是否有效来调用两个不同的函数。
如果您尝试进行某种“基于对象”的编程,它很有用。
如果您看过 Quake 3 引擎的源代码..您可以清楚地看到大多数“实体”都有定义它们的属性以及它们所做的工作[即函数指针]。
分离属性和函数(通过 C 中的函数指针)定义了“结构”对象的属性和它们可以执行的操作。
例如:
struct _man{
char name[];
int age;
void (*speak)(char *text);
void (*eat)(Food *foodptr);
void (*sleep)(int hours);
/*etc*/
};
void grijesh_speak(char *text)
{
//speak;
}
void grijesh_eat(Food *food)
{
//eat
}
void grijesh_sleep(int hours)
{
//sleep
}
void init_struct(struct _man *man)
{
if(man == NULL){ man = malloc(sizeof(struct _man));}
strcpy(*man.name,"Grijesh");
man->age = 25;
man->speak = grijesh_speak;
man->eat = grijesh_food;
man->sleep = grijesh_sleep;
//etc
}
//so now in main.. i can tell you to either speak, or eat or sleep.
int main(int argc, char *argv[])
{
struct _man grijesh;
init_struct(&grijesh);
grijesh.speak("Babble Dabble");
grijesh.sleep(10);
return 0;
}
我过去曾使用它在 C 中实现通用容器1。
例如:
typedef struct generic_list_node {
void *data;
struct generic_list_node *next;
} generic_list_node_t;
typedef struct generic_list {
generic_list_node_t *head;
void *(*copy)(void *data);
void (*delete)(void *data);
int (*compare)(void *lhs, void *rhs);
void (*display)(void *data, FILE *stream);
} generic_list_t;
列表结构本身与数据无关,使用
void *
来表示数据项,并将所有类型感知操作委托给上面指针指示的函数:
int insert(generic_list_t l, void *data)
{
generic_list_node_t *cur = l.head;
generic_list_node_t *new = malloc(sizeof *new);
if (new)
{
new->data = l.copy(data);
new->next = NULL;
if (l.head == NULL)
{
l.head = new;
}
else
{
while (cur->next && l.compare(new->data, cur->data) > 0)
cur = cur->next;
new->next = cur->next;
cur->next = new;
printf("Successfully added ");
l.display(data, stdout);
printf(" to list\n");
}
return 1;
}
return 0;
}
1。对于“通用”和“容器”的适当宽松的定义
这在嵌入式系统或驱动程序编写中特别有用。 使用函数指针调用函数。
例如
struct_my_filesystem.open=my_open;
struct_my_filesystem.read=my_read;
等等
有时在 C 中,您需要调用一个函数,而不预先知道它的实现。例如。如果您正在开发用于不同项目的独立库。在这种情况下,将函数指针添加到上下文结构并将其传递给库函数是非常有意义的。然后,库函数可以在运行时调用您的函数,而无需包含定义它的头文件。
这确实与您进行面向对象编程时所做的类似。在 C 中,您通常传递上下文变量,例如一个结构体,将一组变量和可能对该上下文有意义的函数组合在一起。这与 OO 编程中的等价物很接近,您实例化一个类并在实例上设置所需的变量。
这是一个帮助解释函数指针有用性的项目。尝试创建一个基于 C 的库,提供继承和多态性。或者,尝试重新创建“C with Classes”。结构内部的函数指针至关重要。 http://www.cs.rit.edu/~ats/books/ooc.pdf