您的位置:首页 > 编程语言 > C语言/C++

C语言可变长参数实现“多态”

2013-12-02 10:30 274 查看

一、问题来源

先看看困惑来来源:



这让我很疑惑,难道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) )


2.可变长参数的宏介绍:

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:         kehr163@163.com
* @Created Time: 2013年11月30日 星期六 19时06分32秒
* @Copyright:    GPL 2.0 applies
* @Purpose:      测试可变长参数,实现c的“多态”
*************************************************************************/
#include <stdio.h>
#include <stdarg.h>

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);

}


那么这个清楚了以后,用来实现c的“多态”就好办了。修改上面的代码,实现“多态”:

/*************************************************************************
* @File Name:    test.c
* @Author:       kehr
* @Mail:         kehr163@163.com
* @Created Time: 2013年11月30日 星期六 19时06分32秒
* @Copyright:    GPL 2.0 applies
* @Purpose:      测试可变长参数,实现c的“多态”
*************************************************************************/
#include <stdio.h>
#include <stdarg.h>
#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);
}


结果如下:




三、IDE

(我用的是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有关


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息