首页 > C面向对象之透明指针的运用

C面向对象之透明指针的运用

不透明指针(opaque pointer)可以用来在C中实现封装。

什么是不透明指针(opaque pointer)

从字面意思来看,“不透明”意味着看不到内部,因此“不透明指针”即看不到内部定义的指针。这样说有些抽象,我们来看个例子:

#include 
typedef void   *opque_data;
typedef struct AAA *opque_stru;int main()
{opque_data data = 0;opque_stru stru = 0;printf("Hello, World! 
");return 0;
}

上面的程序可以build通过(也许你会觉得疑惑),data和stru 指针所指的type(AAA)细节是什么,我们不得而知。我们可以自由的操纵这种指针,但无法解引用,即无法查看指针所指向结构的内部信息,只有接口的实现才有这种特权。

透明指针面向对象应用

void *型指针作为一种通用的指针,可以和其它任何类型的指针(函数指针除外)相互转化而不需要类型强制转换,但不能对它进行解引用及下标操作。

在.h文件中声明不包含任何实现细节的结构体,在.c中定义与数据结构的特定实现函数。用一个链表的代码(来自《深入理解C指针》)来说明透明指针的用法。

下面链表的代码中,link并没有与具体的data绑定,而是关联一个void *Data.

link.h

#ifndef LINK_H
#define LINK_Htypedef 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 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_Htypedef 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 
#include 
#include 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	 title: %s	age: %d
", personPtr->firstName, personPtr->firstName, personPtr->lastName, personPtr->title, personPtr->age);
}

main.c

#include "link.h"
#include "person.h"
#include 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;
}

更多相关:

  • 文章目录前言封装C++实现C 实现继承C++ 实现C实现 前言 为了保证代码的可复用性、可扩展性、可维护性,我们提出了面向对象的思想。 面向对象的核心特性有以下几个 封装特性 信息隐藏或者数据访问保护。类通过暴露有限的访问接口,授权外部仅能通过类提供的方式来访问内部信息或者数据。 封装用来提升代码的可扩展性、可维护性继承特...

  • 容器选择 取的元素很多,频繁的增删元素:linkedlist 涉及到增删,不频繁:linkedlist,arraylist 涉及到了增删,同时涉及到了查询:建议使用arraylist【一般情况增删不多,查询多】   Set:没有顺序,元素不可以重复 Set集合的功能和collection的功能是一致的。   Set两大子类 Hashs...

  • 创建新对象有两种不同的方法: 定义并创建对象的实例使用函数来定义对象,然后创建新的对象实例1.定义并创建对象的实例 var person=new Object(); person.firstname="John"; person.lastname="Doe"; person.age=50; person.eyecolor="blue...

  • 1、引用命名空间: using System.Runtime.Serialization; 2、json的序列化和反序列化的方法: publicclass JsonHelper {///

    /// 序列化/////////
  • 学习计划 MyPlan11 主题:Python描述统计、简单统计图形 时间:8.5-8.11周内完成 参考资料:新书《谁说菜鸟不会数据分析python篇》 各位星友们,在这个星球里每个人都要逼迫自己学习未知的领域或知识点,每天进步一点点,积累的时间久了 ,菜鸟也能起飞。 完成情况: 在pandas中,使用describe函数进行描述统...

  • 利用SocketServer模块来实现网络客户端与服务器并发连接非阻塞通信。 首先,先了解下SocketServer模块中可供使用的类: BaseServer:包含服务器的核心功能与混合(mix-in)类挂钩;这个类只用于派生,所以不会生成这个类的实例;可以考虑使用TCPServer和UDPServer。 TCPServer/UDPS...

  • 题目:序列化二叉树 请实现两个函数,分别用来序列化和反序列化二叉树。 示例:  你可以将以下二叉树:     1    /   2   3      /     4   5 序列化为 "[1,2,3,null,null,4,5]" 解题: /*** Definition for a binary tree no...

  • sd.js  import $global from "./global"; import $g from "./sg"; import $ from "jquery"; import {Message, Loading} from "element-ui";//引入饿了么相关组件 import {Base64} from "js-...

  •     原生sd.js----------------------------------------------------------------  const API_ROOT_URL = "http://www.api.com";const $d= {_postList_url: API_ROOT_URL + "/api...