不透明指针(opaque pointer)可以用来在C中实现封装。
什么是不透明指针(opaque pointer)
从字面意思来看,“不透明”意味着看不到内部,因此“不透明指针”即看不到内部定义的指针。这样说有些抽象,我们来看个例子:
#include <stdio.h>
typedef void *opque_data;
typedef struct AAA *opque_stru;
int main()
{
opque_data data = 0;
opque_stru stru = 0;
printf("Hello, World! \n");
return 0;
}
上面的程序可以build通过(也许你会觉得疑惑),data和stru 指针所指的type(AAA)细节是什么,我们不得而知。我们可以自由的操纵这种指针,但无法解引用,即无法查看指针所指向结构的内部信息,只有接口的实现才有这种特权。
透明指针面向对象应用
void *型指针作为一种通用的指针,可以和其它任何类型的指针(函数指针除外)相互转化而不需要类型强制转换,但不能对它进行解引用及下标操作。
在.h文件中声明不包含任何实现细节的结构体,在.c中定义与数据结构的特定实现函数。用一个链表的代码(来自《深入理解C指针》)来说明透明指针的用法。
下面链表的代码中,link并没有与具体的data绑定,而是关联一个void *Data.
link.h
#ifndef LINK_H
#define LINK_H
typedef void* Data; /* opaque pointer */
typedef struct _linkedList LinkedList;
LinkedList* getLinkedListInstance();
void removeLinkedListInstance(LinkedList* list);
void addNode(LinkedList*, Data);
Data removeNode(LinkedList *);
#endif
link.c
#include "link.h"
#include <stdlib.h>
typedef struct _node{
Data* data; /*here use “Data data;” is also ok */
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); /* potential memeory leak,
it denpeds on if any pointer inside real type of 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 = tmp->data;
list->head = list->head->next;
free(tmp); /* only free node, data is not free here */
return data; /* notes: data inside node returned, client need to free it, */
}
}
下面我们定义一个具体的node 数据类型Person.
person.h
#ifndef PERSON_H
#define PERSON_H
typedef struct _person{
char* firstName;
char* lastName;
char* title;
unsigned int age;
} Person;
void initPerson(Person *personPtr, const char* firstNamePtr, const char* lastNamePtr, const char* titlePtr, unsigned int age);
void delePerson(Person *personPtr);
void dispPerson(Person *personPtr);
#endif
person.c
#include "person.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void initPerson(Person *personPtr,
const char* firstNamePtr,
const char* lastNamePtr,
const char* titlePtr,
unsigned int age)
{
personPtr->firstName = (char *)malloc(strlen(firstNamePtr) + 1);
strcpy(personPtr->firstName, firstNamePtr);
personPtr->lastName = (char *)malloc(strlen(lastNamePtr) + 1);
strcpy(personPtr->lastName, lastNamePtr);
personPtr->title = (char *)malloc(strlen(titlePtr) + 1);
strcpy(personPtr->title, titlePtr);
personPtr->age = age;
}
void delePerson(Person *personPtr)
{
free(personPtr->firstName);
free(personPtr->lastName);
free(personPtr->title);
}
void dispPerson(Person *personPtr)
{
printf("%s info name: %s %s\t title: %s\tage: %d\n",
personPtr->firstName,
personPtr->firstName,
personPtr->lastName,
personPtr->title,
personPtr->age);
}
main.c
#include "link.h"
#include "person.h"
#include <stdio.h>
int main(int argc, char **argv)
{
LinkedList *list = getLinkedListInstance();
Person *person = (Person *)malloc(sizeof(Person));
initPerson(person, "Ricky", "ZEK", "Acmen", 36);
addNode(list, person);
person = (Person *)malloc(sizeof(Person));
initPerson(person, "John", "OPP", "Develop", 28);
addNode(list, person);
person = (Person *)malloc(sizeof(Person));
initPerson(person, "Ami", "VIV", "pet", 2);
addNode(list, person);
person = removeNode(list);
dispPerson(person);
delePerson(person);
free(person);
person = removeNode(list);
dispPerson(person);
delePerson(person);
free(person);
removeLinkedListInstance(list); /*memory leak, you can think of it */
return 0;
}