不使用C++时,很多C语言新手可能认为C语言缺乏了面向对象和抽象性,事实上,C语言通过某种组合方式,可以间接性的实现面对对象和抽象。

不过多态和继承这种实现,就有点小麻烦,但是依然可以实现。

核心:

利用 void 类型指针,可以指向任意类型指针。

1 //基本代码
2 void* p;
3 p = (void*) "HelloWorld";
4
5 char* str;
6 str = (char*) p;
7
8 printf("%s",str);//输出 HellWord

通过这个我们就可以实现抽象性,让数据结构或函数不再与特定的类型高耦合。

从而像C++模板一样,处理任何类型元素。

面向对象的类概念:

类自身会有一组属性和一组公开或私有的方法函数,外界可以实例化一个,从而创建一个类的对象。

这在C语言里面,可以通过 struct 关键字来定义类似于类的概念结构。

我们现在来实现一组抽象的面向对象类的列表容器(List),可以装载任意对象指针:

#include <stdio.h>
#include <stdlib.h> #define SIEZ_NAME 200
#define Class struct //双向链表
typedef Class Struct_List_Node{
void * item;
struct Struct_List_Node * next;
struct Struct_List_Node * previous;
}WList_Node; typedef Class Struct_WList{
//类的属性
WList_Node* head;
WList_Node* end;
int length; //公开方法函数
void (*push)(Class Struct_WList*,void*);
void (*destroy)(Class Struct_WList* );
void* (*pop)(Class Struct_WList* );
void* (*shift)(Class Struct_WList* ); }WList; void WList_push(WList* self,void* item){
WList_Node* new_node = (WList_Node* )malloc(sizeof(WList_Node));
new_node->item = item;
new_node->next = NULL;
new_node->previous = NULL;
printf("Push %p\n", new_node);
self->length++;
if(self->head == NULL){
self->head = self->end = new_node;
}else{
new_node->previous = self->end;
self->end = self->end->next = new_node;
} } void* WList_pop(WList* self){
if(self->length <= 0 )return NULL;
WList_Node* pop_node;
self->length--;
pop_node = self->end;
pop_node->previous->next = NULL;
void* return_p = pop_node->item;
free(pop_node);
return return_p; } void* WList_shift(WList* self){
if(self->length <= 0 )return NULL;
WList_Node* pop_node;
self->length--;
pop_node = self->head;
self->head = self->head->next;
self->head->previous = NULL;
void* return_p = pop_node->item;
free(pop_node);
return return_p;
} void WList_destroy(WList* self){
WList_Node* destroy_node;
while(self->head){
destroy_node = self->head;
self->head = self->head->next;
printf("WList_destroy: %p\n",destroy_node);
free(destroy_node);
}
} void WList_init(WList* self){
self->length = 0;
self->head = self->end = NULL;
self->push = WList_push;
self->pop = WList_pop;
self->shift = WList_shift;
self->destroy = WList_destroy;
} //测试类型
typedef Class struct_book{
char name[SIEZ_NAME];
int price;
}Book; int main(){
//测试
WList* list = (WList*) malloc(sizeof(WList)); WList_init(list); list->push(list,"Head !");//C可以省略强制转换,但不建议
list->push(list,(void *)'S');
list->push(list,(void *)66666);
list->push(list,(void *)2);
list->push(list,(void *)(char *) malloc(sizeof(char)*10));
list->push(list,(void *)"wc");
list->push(list,(void *)(char *) malloc(sizeof(char)*10));
list->push(list,(void *)(char *) malloc(sizeof(char)*52));
list->push(list,(void *)(char *) malloc(sizeof(char)*100));
list->push(list,(void *)(Book *) malloc(sizeof(Book)*10));
list->push(list,(void *)"HelloWorld!!!!"); printf("\nFrist List length:%d\n\n", list->length);
printf("Head String: %s \n\n",(char *) list->shift(list));
printf("End String: %s \n\n", list->pop(list));
printf("List length:%d\n", list->length); list->destroy(list); getchar();
return 0;
}

这样我们就创建了解耦的通用列表容器。init相当于构造函数,destroy相当于析构函数。

仔细观察代码,编程list->xxx 即可以使用所有本身的公开函数,只是初始化的时候需要使用一下init函数。

然后我们每次将第一个参数作为自身传递,即可以像Python面向对象一样(虽然它自动传递),实现面向对象的类。

当然了,面向对象不止包括类,还有多态,抽象,接口,继承等等一系列行为,这些在C语言实现略为麻烦。

http://www.cnblogs.com/suwings/p/6500571.html

C语言利用 void 类型指针实现面向对象类概念与抽象的更多相关文章

  1. C语言利用 void 类型指针实现面向对象类概念与抽象。

    不使用C++时,很多C语言新手可能认为C语言缺乏了面向对象和抽象性,事实上,C语言通过某种组合方式,可以间接性的实现面对对象和抽象. 不过多态和继承这种实现,就有点小麻烦,但是依然可以实现. 核心: ...

  2. C语言-(void*)类型指针

    (void*)类型指针:ANSI新增的:即定义了一个指针,但不指定指向任何类型(即指向抽象的数据类型). 1 通过强制类型转换可将其值赋给另一指针变量 2.1用于动态存储函数的返回型指针 void m ...

  3. C语言之void类型及void指针 分类: C/C++ 2015-07-13 11:24 8人阅读 评论(0) 收藏

    原文网址:http://www.cnblogs.com/pengyingh/articles/2407267.html 1.概述 许多初学者对C/C 语言中的void及void指针类型不甚理解,因此在 ...

  4. void类型指针的基本用法

    void作为指针时可以用任意类型的的指针值都可以给它进行赋值和传递,但是输出时必须时显性输出 代码如下: #include<cstdio> #include<iostream> ...

  5. Atitit java方法引用(Method References) 与c#委托与脚本语言js的函数指针

    Atitit java方法引用(Method References) 与c#委托与脚本语言js的函数指针   1.1. java方法引用(Method References) 与c#委托与脚本语言js ...

  6. void类型及void指针

    1.概述 许多初学者对C/C 语言中的void及void指针类型不甚理解,因此在使用上出现了一些错误.本文将对void关键字的深刻含义进行解说,并 详述void及void指针类型的使用方法与技巧. 2 ...

  7. void*类型的指针

    void*是一种特殊的指针类型,可以用来存放任意对象的地址.一个void*指针存放着一个地址,这一点和其他指针类似.不同的是,我们对它到底储存的是什么对象的地址并不了解: 比如:double a=2. ...

  8. C语言 详解多级指针与指针类型的关系

    //V推论①:指针变量的步长只与‘指针变量的值’的类型有关(指针的值的类型 == 指针指向数据的类型) //指针类型跟指针的值有关,指针是占据4个字节大小的内存空间,但是指针的类型却是各不相同的 // ...

  9. void类型及void指针(转载)

    转载 https://www.cnblogs.com/pengyingh/articles/2407267.html 2.void的含义 void的字面意思是“无类型”,void *则为“无类型指针” ...

随机推荐

  1. webpack简短版零工程构建项目(二)

    webpack使用总结 1.初始化一个项目 npm init -y 之后会生成一个package.json配置文件. 2.安装webpack,vue,vue-loader npm install we ...

  2. DedeCMS筛选简单实现方法不改后台源文件

    笔者在前面几篇文章中提到的dedecms筛选的实现方法,对新手来说实现过程较复杂.接下来分享一个最简单的实现在移动端上筛选功能. 最近在筹备移动端企业站,实现功能有:实现一个管理后台管理PC端和移动端 ...

  3. JS文字特效:彩色滚动变幻效果,只适合少量的文字。(过多对页面有影响)

    JS代码如下: 代码具体是在哪里的我不知道但是我的有道云上有.如有哪位朋友知道,还望联系下,添加出处. <div id="chakhsu"></div> & ...

  4. python_webApp

    提高开发效率:当更改代码后,不重启服务器就能使用新效果 参考链接:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df ...

  5. 紫书 习题 10-7 UVa 10539(long long + 素数筛)

    注意要开long long 如果int * int会炸 那么久改成long long * int #include<cstdio> #include<vector> #incl ...

  6. [CQOI2013]新Nim游戏(线性基)

    P4301 [CQOI2013]新Nim游戏 题目描述 传统的Nim游戏是这样的:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量可以不同).两个游戏者轮流操作,每次可以选一个火柴堆拿走若干根火柴. ...

  7. HDU 4976 A simple greedy problem. 贪心+DP

    题意: 给定n<=1000个小兵,A每次都能使小兵掉1点血,B每次能使所有小兵掉1点血,A.B轮流攻击,每次轮到A他会选择是否攻击,轮到B必须攻击.求A最多能杀死多少小兵.(当小兵血量为1时被攻 ...

  8. HDU 4923 Room and Moor (单调栈)

    题意: 给你一个A数列,让你求一个单调递增的B数列(0<=bi<=1),使得sum{(ai-bi)^2}最小. 思路: 很明显,如果A = 0...01...1,那么bi=ai即可. 可以 ...

  9. ArcGIS api for javascript——地理处理任务-计算一个可视域

    描述 本例展示了使用一个地理处理计算一个可视域(viewshed) 单击地图上的任意点查看该点5英里内能看见的所有区域.这个模型需要几秒钟来运行并反馈结果. 可视域计算是通过ArcGIS Server ...

  10. bzoj2843极地旅行社题解

    题目大意 有n座小岛,当中每一个岛都有若干帝企鹅. 一開始岛与岛之间互不相连.有m个操作.各自是在两个岛之间修一座双向桥,若两岛已连通则不修并输出no,若不连通就输出yes并修建.改动一个岛上帝企鹅的 ...