Chinaunix首页 | 论坛 | 博客
  • 博客访问: 460264
  • 博文数量: 105
  • 博客积分: 2258
  • 博客等级: 大尉
  • 技术积分: 922
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-23 13:21
文章分类

全部博文(105)

文章存档

2013年(1)

2012年(10)

2011年(94)

分类: C/C++

2011-08-24 17:52:19

  C++中,我们很容易就可以实现函数重载,特别是类的同名方法(多态)。那么,在C语言中我们可以有类似的应用吗?
    
下面先给出我的说明代码,再做解释:
//-----------------------------------------------------------//
#include

 

struct A

{

    // this is data

    int data;

    // this is operation

    void *(*function)();

};

 

void myfun1()

{

    printf("this is fun()\n");

    return;

}

int myfun2(int a)

{

    printf("this is fun(%d)\n", a);

    return a;

}

char myfun3(int a)

{

    printf("this is fun(%c)\n", a);

    return a;

}

int main(void)

{

    struct A a;

 

    a.function = (void *)myfun2;

    a.function('a');

 

    a.function = (void *)myfun3;

    a.function('a');

 

    return 0;

}

//-----------------------------------------------------------//
GCC下编译运行的结果如下:

//-----------------------------------------------------------//
[zonwang@be-rdcnasbd1 test] cc -c -g fun_point.c      

 

[zonwang@be-rdcnasbd1 test] cc -o fun_point fun_point.o

 

[zonwang@be-rdcnasbd1 test] ./fun_point

this is fun(97)

this is fun(a)
//-----------------------------------------------------------//

现在分析一下上面的代码:

首先,这个程序的思路是想用一个结构体模拟一个类,通过函数指针来申明方法,并模拟多态性。
        void* (*fun)();
--------(1
是一个函数指针,注意,这里不要写成
        void (*fun)();
--------(2
接下来写了两个函数
    void myfun1()

    int myfun2(int)

在接下来的main函数中,我们为A实例afun域赋值,这里我们直接赋值了myfun2,若上面方法申明中采用(2),那么将不能把myfun2赋值 fun,因为void*是可以指向任何类型的指针,那么当然可以指向int。这里又定义了myfun3就是为类看看void*是否能自动的转化为 char类型了。
   
另外要说明的一点就是,调用a.fun时我实验了几种调用方法,如程序中所示,它对行参没有任何要求,在本例中,由于传入的是myfun2(int), 不加任何参数调用a.fun(),那么输入的int将随机而定;若参数多于两个,则只有第一个参数有效,其余参数被呼略掉;若第一个参数与所传入的函数不 匹配,则虽然可以通过编译,但结果一般会与期望的不同(错误)。
   
那么,它是否是多态呢?显然不是的,多态是个运行时概念,若想在C里面用同名函数则必须如此利用函数指针,在使用不同的重载形式前必须给函数指针赋上相应的函数才行,在本例中,若要用重载型myfun3的话,在调用a.fun(...)前必须有这样一行
    a.fun=myfun3;
这是因为C毕竟还是一个静态语言的原因。

   
这种结构体与函数指针的结合使用还有很多用途,其实也可以将公用体与函数指针结合,方法一样。这几种结合功能相当强大。在定义接口时将非常有用。
   
比如在写一个设备驱动程序时,我们就要填写一个数据结构file_operations,具体的定义如下:

struct file_operations {
int (*seek) (struct inode * ,struct file *, off_t ,int);
int (*read) (struct inode * ,struct file *, char ,int);
int (*write) (struct inode * ,struct file *, off_t ,int);
int (*readdir) (struct inode * ,struct file *, struct dirent * ,int);
int (*select) (struct inode * ,struct file *, int ,select_table *);
int (*ioctl) (struct inode * ,struct file *, unsined int ,unsigned long
int (*mmap) (struct inode * ,struct file *, struct vm_area_struct *);
int (*open) (struct inode * ,struct file *);
int (*release) (struct inode * ,struct file *);
int (*fsync) (struct inode * ,struct file *);
int (*fasync) (struct inode * ,struct file *,int);
int (*check_media_change) (struct inode * ,struct file *);
int (*revalidate) (dev_t dev);
}
   
这个数据结构为编程人员提供了一个访问设备的公用接口,比如read,write等等。
具体设备驱动程序的编写已经超出本文范围,日后再说明。

小结:
    利用函数指针来模拟多太,讨论出函数指针的一些特殊用法。以及调用函数指针的参数无关性。  

 

阅读(3277) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~