不透明指针
C 不支持面向对象编程,不过,借助不透明指针,我们也可以使用 C 封装数据以及支持某种程度的多态行为。我们可以隐藏数据结构的实现和支持函数,用户没有必要知道数据结构的实现细节,减少这些实现细节就可以降低应用程序的复杂度。此外,这样也不会引诱用户使用数据结构的内部细节,如果用户使用了,之后数据结构的实现发生变化后会导致问题。
说的直白一点就是,你不能通过该指针访问任何元素。
创建和使用不透明指针 不透明指针用来在 C 中实现数据封装。一种方法是在头文件中声明不包含任何实现细节的结构体,然后在实现文件中定义与数据结构的特定实现配合使用的函数。数据结构的用户可以看到声明和函数原型,但是实现会被隐藏(在 .c/.obj 文件中)。只有使用数据结构所需的信息会对用户可见,如果太多的内部信息可见,用户可能会使用这些信息,从而产生依赖。一旦内部结构发生变化,用户的代码可能就会失效。我们创建一个简单的链表来演示不透明指针的用法。
link.h
1 2 3 4 5 6 7 8 9 10 11 12 #ifndef TEST_C_LINK_H #define TEST_C_LINK_H typedef void *Data;typedef struct _linkedList LinkedList ;LinkedList* getLinkedListInstance () ;void removeLinkedListInstance () ;void addNode (LinkedList*, Data) ;Data removeNode (LinkedList*) ;#endif
Data 声明为 void 指针,这样允许实现处理任何类型的数据。LinkedList 的类型定义用了名为 _linkedList 的结构体,这个结构体的定义在实现文件中,对用户隐藏。我们提供来四种方法来使用链表。getLinkedListInstance() 函数获取 LinkedList 实例,一旦不再需要链表就应该调用 removeLinkedListInstance() 函数来释放内存。通过传递链表指针可以让函数处理一个或多个链表。
要将数据添加到链表,需要用 addNode() 函数,我们给它传递链表和要添加到链表的数据指针。removeNode() 函数会返回链表头部的数据。我们把链表的实现在名为 link.c 的独立文件中。
link.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 #include <stdlib.h> #include "link.h" typedef struct _node { Data *data; struct _node *next ; } Node; struct _linkedList { Node *head; }; LinkedList *getLinkedListInstance () { LinkedList *list = (LinkedList *) malloc (sizeof (LinkedList)); list ->head = NULL ; return list ; } void removeLinkedListInstance (LinkedList *list ) { Node *tmp = list ->head; while (tmp != NULL ) { free (tmp->data); Node *current = tmp; tmp = tmp->next; free (current); } free (list ); } void addNode (LinkedList *list , Data data) { Node *node = (Node *) malloc (sizeof (Node)); node->data = data; if (list ->head == NULL ) { list ->head = node; node->next = NULL ; } else { node->next = list ->head; list ->head = node; } } Data removeNode (LinkedList *list ) { if (list ->head == NULL ) { return NULL ; } else { Node *tmp = list ->head; Data *data; list ->head = list ->head->next; data = tmp->data; free (tmp); return data; } }
一个简单的链表就实现好了,那么我们怎么使用呢?
test.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <stdio.h> #include <stdlib.h> #include "link.h" typedef struct { char *username; int age; }Person; void displayPerson (Person*) ;int main () { LinkedList *list = getLinkedListInstance(); Person *person = (Person *)malloc (sizeof (Person)); person->username = "jack" ; person->age = 12 ; Person *person2 = (Person *)malloc (sizeof (Person)); person2->username = "jobs" ; person2->age = 15 ; addNode(list , person); addNode(list , person2); person = removeNode(list ); displayPerson(person); person = removeNode(list ); displayPerson(person); removeLinkedListInstance(list ); return 0 ; } void displayPerson (Person *person) { printf ("username is : %s, age is : %d\n" , person->username, person->age); }
LinkedList 就是一个不透明指针,LinkedList 中的成员对使用者隐藏,只提供必要的方法给使用者,隐藏了实现细节。这个就类似于面向对象中的封装。
参考