赞
踩
封装就是隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别,将抽象得到的数据和行为相结合,形成一个有机的整体,形成“类”,其中数据和函数都是类的成员。
继承即派生类继承了基类的成员变量和成员函数,使子类拥有和父类相同的行为。
多态同一个行为具有多个不同表现形式或形态的能力。在C++中具有继承关系的子类对象和父类对象对外提供一系列统一的接口,在外部调用时会根据对象类型产生不同的结果。
在一个类里面包含了成员变量和成员函数,成员变量代表类的属性,成员函数代表类的行为,C语言本身是一门结构化的语言,不直接直接面向对象的编程,但是面向对象只是一种编程手法,通过使用结构体和函数也可以实现同样的功能。
以顺序表为例,首先是顺序表数据成员,里面包含了长度信息和一个头指针,在C语言中并不支持模板类型,如果要存储任意类型的数据,只能存储对应数据的首地址,当需要存储的时候把地址放入到表中,拿出来后做强制转换,然后进行数据操作。
Vector是void类型,这样的作用是隐藏内部成员细节,相当于C++中的private成员。
typedef void* VectorNode;
typedef void Vector;
typedef struct
{
int length;
VectorNode* head;
}vector_def;
在C++中如果要构建一个对象,这个对象首先会使用构造函数对内部数据进行初始化,并且对象可以构建在堆空间和栈空间上,堆空间的对象可以通过智能指针或者手动释放,栈空间在生命周期结束后就不存在了。
而C语言里面并没有构造函数和析构函数,需要手动构建对象和析构对象,否则就会造成内存泄漏。
在顺序表这个实验里面表的空间是需要动态申请的,因此构造函数也从堆空间申请内存进行对象构建。
Vector* vector_create(int length) { vector_def* ret = NULL; if(length > 0) { ret = malloc(sizeof(vector_def)); ret->head = malloc(sizeof(VectorNode) * length); if(ret && ret->head) { ret->length = length; for(int i = 0; i < length; i++) { ret->head[i] = NULL; } } } return (Vector*)ret; } void vector_clear(Vector* list) { if(list) { free(((vector_def*)list)->head); free(list); } }
在一个类中除了成员变量还有对应的成员函数,C++在调用时候会传递对象地址用于在成员函数中访问成员变量,并且隐藏了实现细节,C语言里面需要显式传递对象地址,这样才能访问到成员变量,并且由于函数参数中包含了对应类型的变量,因此该函数只能被该类使用。
下面使用顺序表的基本操作来进行演示,这三个函数是需要提供给外部使用的,相当于公有成员函数:
bool vector_insert(Vector* list, int i, const VectorNode node) { bool ret = true; vector_def* obj = (vector_def*)list; if(obj && (i >= 0) && (i < obj->length) && node) { for(int j = obj->length - 1; j > i; j--) { obj->head[j] = obj->head[j - 1]; } obj->head[i] = node; } else { ret = false; } return ret; } VectorNode vector_remove(Vector* list, int i) { VectorNode ret = NULL; vector_def* obj = (vector_def*)list; if(obj && (i >= 0) && (i < obj->length)) { for(int j = i + 1; j < obj->length; j++) { obj->head[j - 1] = obj->head[j]; } ret = obj->head[i]; } return ret; } bool vector_get(Vector* list, int i, VectorNode* node) { bool ret = true; vector_def* obj = (vector_def*)list; if(obj && (i >= 0) && (i < obj->length) && node) { *node = obj->head[i]; } else { ret = false; } return ret; } int vector_length(Vector* list) { int ret = 0; ret = (list) ? ((vector_def*)list)->length : (0); return ret; }
与公有成员函数相对应的还有私有成员函数,不能被外部进行访问,这时可以使用static修饰对应的成员函数,让该函数只能被内部使用。
子类继承父类之后,在数据成员上面表现为叠加,并且子类可以使用父类的函数。
此处使用链表来进行演示。
typedef void LinkList;
typedef void* LinkListNode;
// 继承父类vector_def
typedef struct
{
vector_def base;
struct link_list_node head;
}link_list_def;
// 链表节点定义
struct link_list_node
{
struct link_list_node* next;
};
创建和销毁链表
LinkList* link_list_create() { link_list_def* list = malloc(sizeof(link_list_def)); if(list) { list->base.length = 0; list->base.head = NULL; list->head.next = NULL; } return (LinkList*)list; } void link_list_clear(LinkList* list) { free(list); }
使用父类的成员函数获取链表长度:
int main()
{
LinkList* list = link_list_create();
printf("%d\n", vector_length(list));
link_list_clear(list);
}
$> ./a.out
0
由于链表的数据插入、移除和获取操作和顺序表不一样,因此需要重新编写相对应的函数:
bool link_list_insert(LinkList* list, int i, const LinkListNode node) { bool ret = true; link_list_def* obj = (link_list_def*)list; if(obj && (i >= 0) && (i <= obj->base.length) && node) { struct link_list_node* current = position(obj, i); if(current) { ((struct link_list_node*)node)->next = current->next; current->next = node; ++obj->base.length; } } else { ret = false; } return ret; } LinkListNode link_list_remove(LinkList* list, int i) { LinkListNode ret = NULL; link_list_def* obj = (link_list_def*)list; if(obj && (i >= 0) && (i < obj->length)) { struct link_list_node* current = link_list_position(obj, i); struct link_list_node* next = (current) ? (current->next) : (NULL); if(current && next) { ret = next; current->next = next->next; --obj->length; } } return ret; } bool link_list_get(LinkList* list, int i, LinkListNode* node) { bool ret = true; link_list_def* obj = (link_list_def*)list; if(obj && (i >= 0) && (i < obj->length) && node) { struct link_list_node* current = position(obj, i); *((struct link_list_node**)node) = current->next; } else { ret = false; } return ret; }
C++中如果一个类中存在虚函数,那么产生的对象都会有一个虚表指针,虚表指针位于对象的最前面,这个虚表指针指向虚函数表,虚函数表在构造函数中初始化,在析构函数中销毁,所以在这两个函数中都不会发生多态行为。
上面的链表继承自顺序表,显然这种继承方式并不好,因此可以将其进行重构,首先定义一个接口 list_vtable_def,里面包含了顺序表和链表的方法,但是并没有具体实现,相当于C++中的纯虚类。
除了相同的接口之外,他们还有一些相同的属性,这些属性用变量来进行表示,在顺序表和链表中,表的长度就是一种属性,由此在派生出一个抽象类 list_def。
C语言如果要实现多态也可以参考C++的内部实现,在基类中增加一个成员虚表指针。
而刚才所说的 list_vtable_def就是一个虚函数表的定义,派生出的每一个对象都会有一个虚表指针,指向对应类的虚函数表,虚表在构造函数中初始化,在析构函数中销毁。
typedef struct
{
bool (*insert)(List* list, int i, const ListNode node);
ListNode (*remove)(List* list, int i);
bool (*get)(List* list, int i, ListNode* node);
int (*length)(List* list);
}list_vtable_def;
typedef struct
{
list_vtable_def* vtable;
int length;
}list_def;
定义好了抽象类之后,前面两个类的定义也需要进行修改:
typedef struct
{
list_def base;
VectorNode* head;
}vector_def;
typedef struct
{
list_def base;
struct link_list_node head;
}link_list_def;
除了需要定义虚函数表之外,每一个不同的类都需要定义一个不同的虚表,将虚表指针指向它,下面来看一下顺序表和链表中的虚表以及他们的构造:
// 定义在vector.c中的虚表 static vector_vtable s_vector_vtable = { .insert = vector_insert, .remove = vector_remove, .get = vector_get, .length = vector_length }; // 构造函数 Vector* vector_create(int length) { vector_def* ret = NULL; if(length > 0) { ret = malloc(sizeof(vector_def)); ret->head = malloc(sizeof(VectorNode) * length); if(ret && ret->head) { ret->base.vtable = &s_vector_vtable; ret->base.length = length; for(int i = 0; i < length; i++) { ret->head[i] = NULL; } } } return (Vector*)ret; }
// 定义在link_list.c中的虚表 static vector_vtable s_link_list_vtable = { .insert = link_list_insert, .remove = link_list_remove, .get = link_list_get, .length = vector_length }; // 构造函数 LinkList* link_list_create() { link_list_def* list = malloc(sizeof(link_list_def)); if(list) { list->base.length = 0; list->base.vtable = &s_link_list_vtable; list->head.next = NULL; } return (LinkList*)list; }
前面定义了虚函数,利用虚函数可以实现多态,对外提供一个统一的接口供应用层调用:
typedef void List; typedef void* ListNode; void list_insert(List* list, int i, ListNode node) { if((*((list_vtable_def**)list))->insert) { (*((list_vtable_def**)list))->insert(list, i, node); } else { LOG(ERR_CONSTRUCT(NullPointer), "insert function not exist in vtable"); } } ListNode list_remove(List* list, int i) { ListNode ret = NULL; if((*((list_vtable_def**)list))->remove) { ret = (*((list_vtable_def**)list))->remove(list, i); } else { LOG(ERR_CONSTRUCT(NullPointer), "remove function not exist in vtable"); } return ret; } ListNode list_get(List* list, int i) { ListNode ret = NULL; if((*((list_vtable_def**)list))->get) { (*((list_vtable_def**)list))->get(list, i, &ret); } else { LOG(ERR_CONSTRUCT(NullPointer), "get function not exist in vtable"); } return ret; } int list_length(List* list) { if((*((list_vtable_def**)list))->length) { return (*((list_vtable_def**)list))->length(list); } else { LOG(ERR_CONSTRUCT(NullPointer), "length function not exist in vtable"); return 0; } }
实现完成之后分别创建一个链表和一个顺序表,然后调用上面的四个函数:
#include "err.h" #include "Vector.h" #include "LinkList.h" #define MAX_LEN 10 struct list_node { struct link_list_node next; int data; }; // 100个链表节点 struct list_node array1[MAX_LEN] = {0}; // 100个顺序表节点 int array2[MAX_LEN]; int main() { LinkList* list = link_list_create(); Vector* vector = vector_create(MAX_LEN); // 将数据插入表中 for(int i = 0; i < MAX_LEN; i++) { array1[i].data = MAX_LEN - i; array2[i] = i; list_insert(list, i, &array1[i]); list_insert(vector, i, &array2[i]); } printf("list length:%d\n", list_length(list)); printf("vector length:%d\n", list_length(vector)); // 输出链表中的值 printf("list:"); for(int i = 0; i < MAX_LEN; i++) { struct list_node* ret = list_get(list, i); printf("%d ", ret->data); } printf("\n"); // 输出顺序表中的值 printf("vector:"); for(int i = 0; i < MAX_LEN; i++) { int* ret = list_get(vector, i); printf("%d ", *ret); } printf("\n"); //移除链表中的数据 while(list_length(list)) { list_remove(list, 0); } printf("list length:%d\n", list_length(list)); printf("vector length:%d\n", list_length(vector)); vector_clear(vector); link_list_clear(list); }
最终的结果
$> ./a.out
list length:10
vector length:10
list:10 9 8 7 6 5 4 3 2 1
vector:0 1 2 3 4 5 6 7 8 9
list length:0
vector length:10
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。