# C面向对象操作库 **Repository Path**: jason0131czy/cc-oop ## Basic Information - **Project Name**: C面向对象操作库 - **Description**: 用c语言实现的模拟面向对象语言编程方式 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 1 - **Created**: 2022-07-25 - **Last Updated**: 2024-05-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 1.C面向对象工具库 ## 1.1 基本介绍 > 在学习了面向对象语言的编程过后,再次用回C,看见了函数指针这个知识点。觉得可以利用这个知识实现C语言模拟面向对象编程的操作。 代码仓库地址:https://gitee.com/jason0131czy/cc-oop C语言中我们使用函数,永远都是用一行语句调用函数,然后传参实现功能。函数的结构较为松散。 而使用了面向对象的编程,则是利用,**对象.函数()**这种调用方式,将一系列同类型的功能,归于一个对象(类)中。分工更加明确,伪代码如图。 ```c void test1(){ queue q; push(q,数据); pop(queue); } void test2(){ queue q = new(q); q.push(数据); q.pop(); } ``` 但纯c中却无法实现这样的方式,因为缺少 **this指针**,不清楚this指针的朋友们可以去了解一下这家伙 。但退而求其次我们也能模拟出类似的效果。 在我目前的工程代码中,我们的操作如下,结构体调用函数指针(本质上就是调用了一个函数),由于函数内部无法知道调用它的是哪一个对象,所以目前只能把调用的对象地址也传进去。 ```c void test3(){ cc_queue_t queue = Queue(); queue->push(queue, 数据); queue->pop(queue); } ``` 这样的话 就实现了结构体调用函数,实现自身对应的功能。每个结构体内部都会有其自身对应的各种函数提供给操作者调用,而不是之前那样散开来。 例如这是queue.h文件中的一些定义,调用宏接口创建队列,使用结构体内置的函数对队列进行操作即可,不清楚的地方目前暂时可以不用在意,后面会慢慢讲。 ```c //宏接口 #define Queue_Size(size) CC_New_Queue("DEFAULT", size) #define Queue() CC_New_Queue("DEFAULT", DEFAULT_VECTOR_CAPACITY) #define Queue_All(name,size) CC_New_Queue(name, size) typedef struct _cc_queue* cc_queue_t; typedef struct _cc_queue cc_queue; struct _cc_queue { cc_vector_t parent; //继承机制 cc_uint32_t size; //实际数量 cc_uint32_t capacity; //容量 cc_bool_t(*isEmpty) (cc_queue_t queue); //是否空 cc_bool_t* (*isFull) (cc_queue_t queue); //是否满 cc_uint32_t(*length) (cc_queue_t queue); //长度 cc_bool_t* (*push) (cc_queue_t queue, void* data); //入队 void* (*pop) (cc_queue_t queue); //出队 void (*clear) (cc_queue_t); //清空队列 void (*free) (cc_queue_t); //消除队列 void (*toString)(cc_queue_t queue, void (*callback)(void* data));//打印队列 }; cc_queue_t CC_New_Queue(cc_uint8_t* name, cc_uint32_t capacity); ``` ## 1.2 库结构 当前 该库结构如下,可利用cc_config.h进行一些全局的配置以及库的裁切,cc_object中是最初始的类定义,以及各种基础的枚举,宏定义等。 - object 初始父类 - cc_config.h 配置文件 - collection 集合 - cc_dqueue 双向链队 - cc_list 双向链表 - cc_lstack 链栈 - cc_queue 数组队列 - cc_stack 数组栈 - cc_vector 存储对象数组 - cc_string 字符串 ## 1.3 测试函数 在main.c中,提供了所有类型的测试函数,通过看测试函数以及对应的头文件可以很快的懂得如何使用。 # 2.Collection 集合 Collection集合是一系列存储对象的数据结构类型的统称,在该分类下,我们会有大量的存储对象的数据结构。 例如Vector,List,Queue等等。现在 让我们开始介绍第一个类。 ## 2.1 Vector类 取名自c++的vector,是一个可以自动增长的对象数组,采用连续的存储空间来存储元素。 有三种创建他的宏方式,具体参数为 该类的名字,以及指定该类初始容量。默认创建时的容量可在cc_config.h中指定 ```c #define Vector_Size(size) CC_New_Vector("DEFAULT", size) #define Vector() CC_New_Vector("DEFAULT", DEFAULT_VECTOR_CAPACITY) #define Vector_All(name,size) CC_New_Vector(name, size) ``` **结构体API** 关于具体如何使用的话,在main.c的测试函数里已经写的很多了。基本阅读测试函数就懂了。**但这里是第一次,所以我们还是从零开始讲一次**,首先可以看cc_vector.h的结构体定义。查看里面有哪些可以用的函数 ![image-20220817202756760](https://coalball-code-image.oss-cn-chengdu.aliyuncs.com/C-OOP/image-20220817202756760.png) 具体使用,其实真的很简单哒,调用接口获取一个vector,然后使用内部的函数即可。 ```c //打印函数的回调 static void print_stu(student_t stu) { printf("Data:%d %s\n", stu->age, stu->name); } //测试 void test_vector(){ cc_vector_t vector = Vector(); //创建一个Vector //查看基本信息 printf("Capacity:%d\n", vector->capacity); printf("Size:%d\n", vector->size); printf("Name:%s\n", vector->parent->name); printf("Type:%d\n", vector->parent->type); printf("Empty:%d\n\n", vector->isEmpty(vector)); //生成测试数据 struct student* stu1 = new(struct student); stu1->age = 18; stu1->name = "Jason"; struct student* stu2 = new(struct student); stu2->age = 38; stu2->name = "Marry"; struct student* stu3 = new(struct student); stu3->age = 28; stu3->name = "Tom"; //插入 vector->insert(vector, stu1, vector->size + 1); vector->insert(vector, stu2, vector->size + 1); vector->insert(vector, stu3, vector->size + 1); //打印vector,如果第二个参数传NULL 就打印里面所有数据的地址 vector->toString(vector, print_stu); //删除第一个学生,并看看是不是删成功 struct student* stu = vector->delete(vector, 1); vector->toString(vector, print_stu); printf("Delete:%d %s \n\n", stu->age, stu->name); //获取指定的数据 stu = vector->get(vector, 1); printf("\nGet:%d %s\n\n", stu->age, stu->name); //清除vector中所有的数据 vector.clear(vector); //释放(销毁)vector vector.free(vector); } ``` ## 2.2 Queue类 继承自Vector的数组队列,先进先出。创建接口 ```c #define Queue_Size(size) CC_New_Queue("DEFAULT", size) #define Queue() CC_New_Queue("DEFAULT", DEFAULT_VECTOR_CAPACITY) #define Queue_All(name,size) CC_New_Queue(name, size) ``` 具体API可见cc_queue.h ## 2.3 Stack类 继承自Vector的数组栈,先进后出。创建接口 ```c #define Stack_Size(size) CC_New_Stack("DEFAULT", size) #define Stack() CC_New_Stack("DEFAULT", DEFAULT_VECTOR_CAPACITY) #define Stack_All(name,size) CC_New_Stack(name, size) ``` 具体API可见cc_stack.h ## 2.4 List类 普普通通的双向链表啦 ```c #define List() CC_New_List("DEFAULT"); ``` ## 2.5 DQueue类 双向链队,左右两边都可以进出 ```c #define DQueue() CC_New_DQueue("DEFAULT") ``` ## 2.6 LStack 链栈 先进后出 ```c #define LStack() CC_New_LStack("DEFAULT") ```