先看看困惑来来源:
这让我很疑惑,难道c也支持“多态”的特性么?貌似没见过呀~
google帮忙,明白了一二,特此记录:
原来这种“多态”是通过c语言的可变长参数实现的(python也具有这种特性)
有关可变长参数的介绍见文章末尾的参考列表,说的很详细。
截取关键的内容:
1.可变长参数的宏定义:
(学习宏函数的典例呀)
// stdarg.h
#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end
// vadefs.h
typedef char * va_list;
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 )
#define _ADDRESSOF(v) ( &(v) )
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
C语言可变参数通过三个宏(va_start、va_end、va_arg)和一个类型(va_list)实现,
void va_start ( va_list ap, paramN );
参数:
ap: 可变参数列表地址
paramN: 确定的参数
功能:初始化可变参数列表(把函数在 paramN 之后的参数地址放到 ap 中)。
void va_end ( va_list ap );
功能:关闭初始化列表(将 ap 置空)。
type va_arg ( va_list ap, type );
功能:返回下一个参数的值。
va_list :存储参数的类型信息。
好了,综合上面3个宏和一个类型可以猜出如何实现C语言可变长参数函数:用 va_start 获取参数列表(的地址)存储到 ap 中,用 va_arg 逐个获取值,最后用 va_arg 将 ap 置空。
按照说明,我实现了一个简单的测试代码,来测试可变长参数:
/*************************************************************************
* @File Name: test.c
* @Author: kehr
* @Mail: [email protected]
* @Created Time: 2013年11月30日 星期六 19时06分32秒
* @Copyright: GPL 2.0 applies
* @Purpose: 测试可变长参数,实现c的“多态”
*************************************************************************/
#include
#include
void show(int first_param,int flag, ...);
int main()
{
show(1,2,3,4,5);
return 0;
}
void show(int first_param,int flag, ...)
{
//定义参数列表
va_list vl;
//初始化参数列表
va_start (vl, flag);
//获取参数值
printf ("%d ",first_param);
printf ("%d ",flag );
printf("%d ",va_arg(vl,int));
printf("%d ",va_arg(vl,int));
printf("%d ",va_arg(vl,int));
printf("\n");
//关闭参数列表
va_end(vl);
}
/*************************************************************************
* @File Name: test.c
* @Author: kehr
* @Mail: [email protected]
* @Created Time: 2013年11月30日 星期六 19时06分32秒
* @Copyright: GPL 2.0 applies
* @Purpose: 测试可变长参数,实现c的“多态”
*************************************************************************/
#include
#include
#define _NAME 0
#define _NAME_AGE 1
void show(int first_param,int flag, ...); //对外暴露的接口
void showName(char* name); //内部的实现
void showNameAndAge(char* name, int age); //内部的实现
int main()
{
//如果不看show的具体实现,那么下面这两句代码不就是“多态”了么?
show(1,_NAME,"xiaogqiang");
show(2,_NAME_AGE,"xiaoqiang",23);
return 0;
}
void show(int first_param,int flag, ...)
{
//这里地一个参数没有做处理,完全可以直接输出,或进行其它处理
printf("%d\n",first_param);
//定义参数列表
va_list vl;
//需要处理的参数
char* name;
int age;
//初始化参数列表
va_start (vl, flag);
//获取参数值
//printf("flag=%d\n",flag);
//printf("name=%s\n",va_arg(vl,char*));
//printf("age=%d\n",va_arg(vl,int));
//单独使用下面这条语句无法得到结果,猜测是printf的内部原因。
//printf("name=%s\n age=%d\n",va_arg(vl,char*),va_arg(vl,int));
//根据标志选择要处理的函数
switch(flag)
{
case _NAME:
showName(va_arg(vl,char*));
break;
case _NAME_AGE:
name = va_arg(vl,char*);
age = va_arg(vl,int);
showNameAndAge(name,age);
break;
default:
printf("没有匹配的函数!\n");
}
//关闭参数列表
va_end(vl);
}
void showName(char* name)
{
printf("name=%s\n",name);
}
void showNameAndAge(char* name, int age)
{
printf("name=%s\nage=%d\n",name,age);
}
(我用的是vim编辑的,可能界面有些人会不习惯。上张我的vim编辑图)
感兴趣的朋友,我可以把我的vimrc共享,目前文件配置超过600行,分割了一下感觉好点了。
vim初用很难受,用久了就月来越离不开了。程序员编程利器,建议学一下。
通过这个例子的测试,我知道C的强大也是毋庸置疑的。面向过程的语言也可以借用面向对象的思想,二者没有绝对的鸿沟。对于C来说,某个方面可能不擅长,但是并不但表做不了。还有许多好玩儿的特性,待我慢慢去挖出来。
这个例子中的思想在c的很多函数都有所体现,除了文章开头介绍的open函数外还有很多。说明了在C的标准实现里面这些特性占据着很重要的的地位。借用面向对象的思想解决问题,这也便是面向过程和面向对象的结合。
最近要写点对面向对象的思考。是时候总结一下了。
http://www.cnblogs.com/chinazhangjie/archive/2012/08/18/2645475.html
http://club.topsage.com/thread-2263309-1-1.html有关