在 C 语言中可以用结构体代替类,用函数指针代替成员方法,实现数据成员与成员方法的封装,在客户端写出的程序与 C++ 类似,唯一的不同是 C 语言中调用函数指针成员时必须将本对象的地址传给函数,因为 C 语言中各函数的地位是相同的。

本文以模仿 STL 中的 vector 类写了一个 C 语言的 vector 结构体,程序如下:

1. vector 的接口

  1. /********************************************************************
  2. created: 2013/08/19
  3. created: 19:8:2013 0:09
  4. file base: vector
  5. file ext: h
  6. author: Justme0 (http://blog.csdn.net/Justme0)
  7.  
  8. purpose: vector 结构体的定义
  9. *********************************************************************/
  10.  
  11. #ifndef _VECTOR_H_
  12. #define _VECTOR_H_
  13.  
  14. typedef struct vector vector;
  15.  
  16. typedef char vec_value_type;
  17. typedef vec_value_type* vec_pointer;
  18. typedef vec_value_type* vec_iterator;
  19. typedef unsigned int vec_size_type;
  20.  
  21. struct vector {
  22. /*
  23. ** 获取下标为 index 的元素
  24. */
  25. vec_value_type (*get_at)(vector *pvec, const int index);
  26.  
  27. /*
  28. ** 设置下标为 index 处的元素为 elem
  29. */
  30. void (*set_at)(vector *pvec, const int index, const vec_value_type elem);
  31.  
  32. vec_iterator (*begin)(vector *pvec);
  33. vec_iterator (*end)(vector *pvec);
  34.  
  35. vec_value_type (*front)(vector *pvec);
  36. vec_value_type (*back)(vector *pvec);
  37.  
  38. int (*size)(vector *pvec);
  39. int (*capacity)(vector *pvec);
  40. int (*empty)(vector *pvec);
  41.  
  42. void (*insert_n)(vector *pvec, const vec_iterator position, const vec_size_type n, const vec_value_type elem);
  43. vec_iterator (*earse_pos)(vector *pvec, const vec_iterator position);
  44. vec_iterator (*earse_int)(vector *pvec, const vec_iterator first, const vec_iterator last);
  45. void (*clear)(vector *pvec);
  46. void (*push_back)(vector *pvec, const vec_value_type elem);
  47. void (*pop_back)(vector *pvec);
  48.  
  49. vec_iterator _start;
  50. vec_iterator _finish;
  51. vec_iterator _end_of_storage;
  52. };
  53.  
  54. void vec_construct(vector *pvec);
  55. void vec_construct_n(vector *pvec, const int size);
  56.  
  57. void vec_destruct(vector *pvec);
  58.  
  59. #endif

2. vector 的实现

  1. /********************************************************************
  2. created: 2013/08/19
  3. created: 19:8:2013 0:09
  4. file base: vector
  5. file ext: c
  6. author: Justme0 (http://blog.csdn.net/Justme0)
  7.  
  8. purpose: vector 的实现
  9. *********************************************************************/
  10.  
  11. #include "vector.h"
  12. #include <math.h>
  13. #include <stdlib.h>
  14. #include <assert.h>
  15.  
  16. #define CHECK_BORDER assert(pvec->_finish >= pvec->_start && pvec->_end_of_storage >= pvec->_start)
  17.  
  18. static vec_iterator copy(vec_iterator first, vec_iterator last, vec_iterator result) {
  19. vec_iterator src = first;
  20. vec_iterator dst = result;
  21. for (; src != last; ++src, ++dst) {
  22. *dst = *src;
  23. }
  24. return dst;
  25. }
  26.  
  27. static vec_value_type _get_at(vector *pvec, int index) {
  28. return *(pvec->begin(pvec) + index);
  29. }
  30.  
  31. static void _set_at(vector *pvec, int index, vec_value_type elem) {
  32. pvec->_start[index] = elem;
  33. }
  34.  
  35. static vec_iterator _begin(vector *pvec) {
  36. return pvec->_start;
  37. }
  38.  
  39. static vec_iterator _end(vector *pvec) {
  40. return pvec->_finish;
  41. }
  42.  
  43. static vec_value_type _front(vector *pvec) {
  44. return *pvec->begin(pvec);
  45. }
  46.  
  47. static vec_value_type _back(vector *pvec) {
  48. return *(pvec->end(pvec) - 1);
  49. }
  50.  
  51. static int _size(vector *pvec) {
  52. return pvec->end(pvec) - pvec->begin(pvec);
  53. }
  54.  
  55. static int _capacity(vector *pvec) {
  56. return pvec->_end_of_storage - pvec->begin(pvec);
  57. }
  58.  
  59. static int _empty(vector *pvec) {
  60. return pvec->begin(pvec) == pvec->end(pvec);
  61. }
  62.  
  63. static void _insert_n(vector *pvec, vec_iterator position, vec_size_type n, const vec_value_type elem) {
  64. vec_size_type old_size = 0;
  65. vec_size_type new_size = 0;
  66. int inset_index = 0;
  67. vec_iterator ite = NULL;
  68.  
  69. assert(pvec->_start <= position && position <= pvec->end(pvec));
  70. CHECK_BORDER;
  71.  
  72. if (0 == n) {
  73. return ;
  74. }
  75.  
  76. inset_index = position - pvec->_start;
  77. old_size = pvec->size(pvec);
  78. new_size = old_size + n;
  79.  
  80. // 先检查剩余空间是否足够,不够则扩容
  81. if ((vec_size_type)(pvec->_end_of_storage - pvec->_finish) < n) {
  82. const vec_size_type new_capacity = old_size + __max(old_size, n);
  83.  
  84. vec_value_type *new_base = (vec_value_type *)realloc(pvec->_start, new_capacity * sizeof(vec_value_type));
  85. if (NULL == new_base) {
  86. exit(OVERFLOW); // 此时原来的空间将发生内存泄漏
  87. }
  88. pvec->_start = new_base;
  89. pvec->_end_of_storage = pvec->_start + new_capacity;
  90. }
  91. pvec->_finish = pvec->_start + new_size;
  92.  
  93. position = pvec->_start + inset_index;
  94. // 移动元素
  95. for (ite = pvec->_finish; ite >= position + n; --ite) {
  96. *ite = *(ite - n);
  97. }
  98. // 插入n个新元素
  99. for (; ite >= position; --ite) {
  100. *ite = elem;
  101. }
  102. }
  103.  
  104. static vec_iterator _earse_pos(vector *pvec, const vec_iterator position) {
  105. if (position + 1 != pvec->end(pvec)) {
  106. copy(position + 1, pvec->_finish, position);
  107. }
  108. --pvec->_finish;
  109. return position;
  110. }
  111.  
  112. static vec_iterator _earse_int(vector *pvec, const vec_iterator first, const vec_iterator last) {
  113. vec_iterator i = copy(last, pvec->_finish, first);
  114. pvec->_finish -= last - first;
  115.  
  116. return first;
  117. }
  118.  
  119. static void _clear(vector *pvec) {
  120. pvec->earse_int(pvec, pvec->begin(pvec), pvec->end(pvec));
  121. }
  122.  
  123. static void _push_back(vector *pvec, const vec_value_type elem) {
  124. CHECK_BORDER;
  125.  
  126. _insert_n(pvec, pvec->end(pvec), 1, elem);
  127. }
  128.  
  129. static void _pop_back(vector *pvec) {
  130. pvec->earse_pos(pvec, pvec->end(pvec) - 1);
  131. }
  132.  
  133. static void set(vector *pvec) {
  134. pvec->_finish = NULL;
  135. pvec->_start = NULL;
  136. pvec->_end_of_storage = NULL;
  137.  
  138. pvec->get_at = _get_at;
  139. pvec->set_at = _set_at;
  140.  
  141. pvec->begin = _begin;
  142. pvec->end = _end;
  143.  
  144. pvec->front = _front;
  145. pvec->back = _back;
  146.  
  147. pvec->size = _size;
  148. pvec->capacity = _capacity;
  149. pvec->empty = _empty;
  150.  
  151. pvec->insert_n = _insert_n;
  152. pvec->earse_pos = _earse_pos;
  153. pvec->earse_int = _earse_int;
  154. pvec->clear = _clear;
  155. pvec->push_back = _push_back;
  156. pvec->pop_back = _pop_back;
  157. }
  158.  
  159. static void reset(vector *pvec) {
  160. pvec->_finish = NULL;
  161. pvec->_start = NULL;
  162. pvec->_end_of_storage = NULL;
  163.  
  164. pvec->get_at = NULL;
  165. pvec->set_at = NULL;
  166.  
  167. pvec->begin = NULL;
  168. pvec->end = NULL;
  169.  
  170. pvec->front = NULL;
  171. pvec->back = NULL;
  172.  
  173. pvec->size = NULL;
  174. pvec->capacity = NULL;
  175. pvec->empty = NULL;
  176.  
  177. pvec->insert_n = NULL;
  178. pvec->earse_pos = NULL;
  179. pvec->earse_int = NULL;
  180. pvec->clear = NULL;
  181. pvec->push_back = NULL;
  182. pvec->pop_back = NULL;
  183. }
  184.  
  185. void vec_construct(vector *pvec) {
  186. set(pvec);
  187. }
  188.  
  189. void vec_construct_n(vector *pvec, const int size) {
  190. set(pvec);
  191.  
  192. pvec->_start = (vec_iterator)malloc(size * sizeof(*pvec->_start));
  193. if (NULL == pvec->_start) {
  194. // TODO:
  195. exit(OVERFLOW);
  196. }
  197.  
  198. pvec->_finish = pvec->_start + size;
  199. pvec->_end_of_storage = pvec->_finish;
  200. }
  201.  
  202. void vec_destruct(vector *pvec) {
  203. free(pvec->_start);
  204.  
  205. reset(pvec);
  206. }

3. 测试程序

  1. /********************************************************************
  2. created: 2013/08/19
  3. created: 19:8:2013 0:10
  4. file base: test
  5. file ext: c
  6. author: Justme0 (http://blog.csdn.net/Justme0)
  7.  
  8. purpose: vector 的测试程序
  9. *********************************************************************/
  10.  
  11. #include "vector.h"
  12. #include <stdio.h>
  13.  
  14. void output(vector *pvec) {
  15. vec_iterator iter;
  16. for (iter = pvec->begin(pvec); iter != pvec->end(pvec); ++iter) {
  17. printf("%c\n", *iter);
  18. }
  19. }
  20.  
  21. int main(int argc, char **argv) {
  22. char ch = 'A';
  23. int cnt = 5;
  24.  
  25. vector my_vec;
  26. vec_construct(&my_vec);
  27.  
  28. while (cnt--) {
  29. my_vec.push_back(&my_vec, ch++);
  30. }
  31. output(&my_vec);
  32.  
  33. puts("set [2]: '2'");
  34. my_vec.set_at(&my_vec, 2, '2');
  35. output(&my_vec);
  36.  
  37. my_vec.empty(&my_vec) ? puts("empty") : puts("not empty");
  38.  
  39. puts("pop_back...");
  40. my_vec.pop_back(&my_vec);
  41. output(&my_vec);
  42. printf("size is %d\n", my_vec.size(&my_vec));
  43.  
  44. printf("back is '%c'\n", my_vec.back(&my_vec));
  45.  
  46. puts("clear...");
  47. my_vec.clear(&my_vec);
  48.  
  49. my_vec.empty(&my_vec) ? puts("empty") : puts("not empty");
  50.  
  51. vec_destruct(&my_vec);
  52.  
  53. return 0;
  54. }

4. 运行结果

  1. A
  2. B
  3. C
  4. D
  5. E
  6. set [2]: '2'
  7. A
  8. B
  9. 2
  10. D
  11. E
  12. not empty
  13. pop_back...
  14. A
  15. B
  16. 2
  17. D
  18. size is 4
  19. back is 'D'
  20. clear...
  21. empty
  22. 请按任意键继续. . .

1、在测试程序中可以看到,定义一个结构体后,必须紧跟着用函数 construct 将对象的成员赋值以初始化,我称这个过程为“构造”。

2、最后必须显示调用 destruct 函数将对象“析构”,释放对象 malloc 的空间。

我将这个程序给某个 C++ 游戏程序员看,被他一阵批,说我的程序最大的缺点就是 不是面向对象;没有一个企业会让这份程序通过;“你写的是 Objective-C 形式”。桑心啊,我只好贴在这独自欣赏了。

C 语言中实现数据与方法的封装的更多相关文章

  1. 最简单删除SQL Server中所有数据的方法

     最简单删除SQL Server中所有数据的方法 编写人:CC阿爸 2014-3-14 其实删除数据库中数据的方法并不复杂,为什么我还要多此一举呢,一是我这里介绍的是删除数据库的所有数据,因为数据之间 ...

  2. 关于VUE调用父实例($parent) 根实例 中的数据和方法

    this.$parent或者 this.$root 在子组件中判断this.$parent获取的实例是不是父组件的实例 在子组件中console.log(this.$parent)  在父组件中con ...

  3. 使用JDBC从数据库中查询数据的方法

    * ResultSet 结果集:封装了使用JDBC 进行查询的结果 * 1. 调用Statement 对象的 executeQuery(sql) 方法可以得到结果集 * 2. ResultSet 返回 ...

  4. Go语言中字符串的查找方法小结

    这篇文章主要介绍了Go语言中字符串的查找方法小结,示例的main函数都是导入strings包然后使用其中的方法,需要的朋友可以参考下   1.func Contains(s, substr strin ...

  5. 返回数据中提取数据的方法(JSON数据取其中某一个值的方法)

    返回数据中提取数据的方法 比如下面的案例是,取店铺名称 接口返回数据如下: {"Code":0,"Msg":"ok","Data& ...

  6. 【类库】私房干货.Net数据层方法的封装

    [类库]私房干货.Net数据层方法的封装 作者:白宁超 时间:2016年3月5日22:51:47 摘要:继上篇<Oracle手边常用70则脚本知识汇总>文章的发表,引起很多朋友关注.便促使 ...

  7. C语言中强制数据类型转换(转)

    原文地址不详 字符型变量的值实质上是一个8位的整数值,因此取值范围一般是-128-127,char型变量也可以加修饰符unsigned,则unsigned char 型变量的取值范围是0-255(有些 ...

  8. 最简单删除SQL Server中所有数据的方法(不用考虑表之间的约束条件,即主表与子表的关系)

    其实删除数据库中数据的方法并不复杂,为什么我还要多此一举呢,一是我这里介绍的是删除数据库的所有数据,因为数据之间可能形成相互约束关系,删除操作可能陷入死循环,二是这里使用了微软未正式公开的sp_MSF ...

  9. C语言中字符数据的输入和输出

    字符的输出 C语言中使用putchar函数来输出字符数据 #include <stdio.h> int main() { char a,b,c,d; //定义字符变量a,b,c,d a = ...

随机推荐

  1. IOS 判断设备类型

    - (NSString*)deviceString { // 需要#import "sys/utsname.h" struct utsname systemInfo; uname( ...

  2. Java中遍历Map对象的方法

    方法一: 在for-each循环中使用entries来遍历 这是最常见的遍历方式,在需要获取key和value时使用. Map<Integer, Integer> map = new Ha ...

  3. ORACLE 视图的 with check option

    ORACLE 视图的 with check option 我们来看下面的例子: create or replace view testview as select empno,ename from e ...

  4. 线程:Exchanger同步工具

    可以在对中对元素进行配对和交换的线程的同步点,类似于交易,A拿着钱到达指定地点,B拿着物品到达指定地点,相互交换,然后各自忙各自的事去了. package ch03; import java.util ...

  5. avalon2学习心得(1)

    github上,avalon2的项目描述是这样的:“avalon2是一款基于虚拟DOM与属性劫持的 迷你. 易用. 高性能 的 前端MVVM框架, 适用于各种场景, 兼容各种古老刁钻浏览器, 吸收最新 ...

  6. const用法总结

    1. const修饰变量 ; const int* a = &b; //情况1 int const* a = &b; //情况2 int* const a = &b; //情况 ...

  7. ArcGIS10.3.1于2015年6月发布

    http://www.esrichina.com.cn/sectorapplication/ArcGIS%2010.3/index.html

  8. MFC之树控件

    树控件对应的类: CTreeControl 树控件属性设置: 启用复选框:Check Boxes = True 父节点显示+-按钮:Has Button = True ; Lines At Roots ...

  9. YUI Array 之each| forEach(遍历)

    1. yui-each原码: 遍历YArray.each = YArray.forEach = Lang._isNative(Native.forEach) ? function (array, fn ...

  10. struts2 0day漏洞

    描述 Apache Struts2 近日出现一个0day漏洞,该漏洞在修补CVE-2014-0050和2014-0094两个安全漏洞处理不当,分别可以导致服务器受到拒绝服务攻击和被执行恶意代码. 漏洞 ...