不使用C++时,很多C语言新手可能认为C语言缺乏了面向对象和抽象性,事实上,C语言通过某种组合方式,可以间接性的实现面对对象和抽象。
不过多态和继承这种实现,就有点小麻烦,但是依然可以实现。
核心:
利用 void 类型指针,可以指向任意类型指针。
//基本代码
void* p;
p = (void*) "HelloWorld";
char* str;
str = (char*) p;
printf("%s",str);//输出 HellWord
通过这个我们就可以实现抽象性,让数据结构或函数不再与特定的类型高耦合。
从而像C++模板一样,处理任何类型元素。
面向对象的类概念:
类自身会有一组属性和一组公开或私有的方法函数,外界可以实例化一个,从而创建一个类的对象。
这在C语言里面,可以通过 struct 关键字来定义类似于类的概念结构。
我们现在来实现一组抽象的面向对象类的列表容器(List),可以装载任意对象指针:
#include
#include
#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 <= )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 <= )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 = ;
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 *));
list->push(list,(void *));
list->push(list,(void *)(char *) malloc(sizeof(char)*));
list->push(list,(void *)"wc");
list->push(list,(void *)(char *) malloc(sizeof(char)*));
list->push(list,(void *)(char *) malloc(sizeof(char)*));
list->push(list,(void *)(char *) malloc(sizeof(char)*));
list->push(list,(void *)(Book *) malloc(sizeof(Book)*));
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 ;
}
这样我们就创建了解耦的通用列表容器。init相当于构造函数,destroy相当于析构函数。
仔细观察代码,编程list->xxx 即可以使用所有本身的公开函数,只是初始化的时候需要使用一下init函数。
然后我们每次将第一个参数作为自身传递,即可以像Python面向对象一样(虽然它自动传递),实现面向对象的类。
当然了,面向对象不止包括类,还有多态,抽象,接口,继承等等一系列行为,这些在C语言实现略为麻烦。
感谢耐心阅读。
C语言利用 void 类型指针实现面向对象类概念与抽象
不使用C++时,很多C语言新手可能认为C语言缺乏了面向对象和抽象性,事实上,C语言通过某种组合方式,可以间接性的实现面对对象和抽象. 不过多态和继承这种实现,就有点小麻烦,但是依然可以实现. 核心: ...
C语言-(void*)类型指针
(void*)类型指针:ANSI新增的:即定义了一个指针,但不指定指向任何类型(即指向抽象的数据类型). 1 通过强制类型转换可将其值赋给另一指针变量 2.1用于动态存储函数的返回型指针 void m ...
void类型指针的基本用法
void作为指针时可以用任意类型的的指针值都可以给它进行赋值和传递,但是输出时必须时显性输出 代码如下: #include #include ...
Atitit java方法引用(Method References)&#160;与c#委托与脚本语言js的函数指针
Atitit java方法引用(Method References) 与c#委托与脚本语言js的函数指针 1.1. java方法引用(Method References) 与c#委托与脚本语言js ...
void类型及void指针
1.概述 许多初学者对C/C 语言中的void及void指针类型不甚理解,因此在使用上出现了一些错误.本文将对void关键字的深刻含义进行解说,并 详述void及void指针类型的使用方法与技巧. 2 ...
void*类型的指针
void*是一种特殊的指针类型,可以用来存放任意对象的地址.一个void*指针存放着一个地址,这一点和其他指针类似.不同的是,我们对它到底储存的是什么对象的地址并不了解: 比如:double a=2. ...
C语言 详解多级指针与指针类型的关系
//V推论①:指针变量的步长只与‘指针变量的值’的类型有关(指针的值的类型 == 指针指向数据的类型) //指针类型跟指针的值有关,指针是占据4个字节大小的内存空间,但是指针的类型却是各不相同的 // ...
void类型及void指针(转载)
转载 https://www.cnblogs.com/pengyingh/articles/2407267.html 2.void的含义 void的字面意思是“无类型”,void *则为“无类型指针” ...
随机推荐
python语言中的编码问题
在编程的过程当中,常常会遇到莫名其妙的乱码问题.很多人选择出了问题直接在网上找答案,把别人的例子照搬过来,这是快速解决问题的一个好办法.然而,作为一个严谨求实的开发者,如果不从源头上彻底理解乱码产生的 ...
人民币大写金额转换C#方法
方法的代码如下: /// /// 人民币大写 /// /// ...
java pdf转换jpg
/** * 把PDF所有页转换为JPG, 并返回所有图片的路劲集合 * @param inputFilePath * 图片路径,具体到文件名 * @param outputFilePath * 输出目 ...
poj3468(线段树 边覆盖)
#include int lb,rb,data; long long sum[5000000],extra[5000000]; void add(int l,int r,i ...
Eclipse使用git 上传代码至github
右击项目,选择Team->Share Project,弹出如下窗口. 选择git,next,在弹出的界面上,①先勾选Use or create……,②createrepository,③勾选工程 ...
java对象和json对象之间互相转换
import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;import java.util.Li ...
03SpringBoot用JdbcTemplates访问Mysql
03SpringBoot用JdbcTemplates访问Mysql 文章指导 学习笔记 学习代码 初始化mysql -- create table `account` DROP TABLE `acco ...
Space Elevator [POJ2392] [DP][优化]
题目大意 n件物品,第i件hi高,有ci件,最高的一件不能超过ai的高度.问最高能堆多高 输入: 第一行,一个n 接下来每一行,为hi,ai,ci 输出,最高堆多高 样例输入: 37 40 35 23 ...
Kotlin入门(9)函数的基本用法
上一篇文章介绍了Kotlin新增的空安全机制,控制语句部分可算是讲完了,接下来将连续描述Kotlin如何定义和调用函数,本篇文章先介绍函数的基本用法. 前面几篇文章介绍控制语句之时,在setOnCli ...