C 语言中实现数据与方法的封装
在 C 语言中可以用结构体代替类,用函数指针代替成员方法,实现数据成员与成员方法的封装,在客户端写出的程序与 C++ 类似,唯一的不同是 C 语言中调用函数指针成员时必须将本对象的地址传给函数,因为 C 语言中各函数的地位是相同的。
本文以模仿 STL 中的 vector 类写了一个 C 语言的 vector 结构体,程序如下:
1. vector 的接口
- /********************************************************************
- created: 2013/08/19
- created: 19:8:2013 0:09
- file base: vector
- file ext: h
- author: Justme0 (http://blog.csdn.net/Justme0)
- purpose: vector 结构体的定义
- *********************************************************************/
- #ifndef _VECTOR_H_
- #define _VECTOR_H_
- typedef struct vector vector;
- typedef char vec_value_type;
- typedef vec_value_type* vec_pointer;
- typedef vec_value_type* vec_iterator;
- typedef unsigned int vec_size_type;
- struct vector {
- /*
- ** 获取下标为 index 的元素
- */
- vec_value_type (*get_at)(vector *pvec, const int index);
- /*
- ** 设置下标为 index 处的元素为 elem
- */
- void (*set_at)(vector *pvec, const int index, const vec_value_type elem);
- vec_iterator (*begin)(vector *pvec);
- vec_iterator (*end)(vector *pvec);
- vec_value_type (*front)(vector *pvec);
- vec_value_type (*back)(vector *pvec);
- int (*size)(vector *pvec);
- int (*capacity)(vector *pvec);
- int (*empty)(vector *pvec);
- void (*insert_n)(vector *pvec, const vec_iterator position, const vec_size_type n, const vec_value_type elem);
- vec_iterator (*earse_pos)(vector *pvec, const vec_iterator position);
- vec_iterator (*earse_int)(vector *pvec, const vec_iterator first, const vec_iterator last);
- void (*clear)(vector *pvec);
- void (*push_back)(vector *pvec, const vec_value_type elem);
- void (*pop_back)(vector *pvec);
- vec_iterator _start;
- vec_iterator _finish;
- vec_iterator _end_of_storage;
- };
- void vec_construct(vector *pvec);
- void vec_construct_n(vector *pvec, const int size);
- void vec_destruct(vector *pvec);
- #endif
2. vector 的实现
- /********************************************************************
- created: 2013/08/19
- created: 19:8:2013 0:09
- file base: vector
- file ext: c
- author: Justme0 (http://blog.csdn.net/Justme0)
- purpose: vector 的实现
- *********************************************************************/
- #include "vector.h"
- #include <math.h>
- #include <stdlib.h>
- #include <assert.h>
- #define CHECK_BORDER assert(pvec->_finish >= pvec->_start && pvec->_end_of_storage >= pvec->_start)
- static vec_iterator copy(vec_iterator first, vec_iterator last, vec_iterator result) {
- vec_iterator src = first;
- vec_iterator dst = result;
- for (; src != last; ++src, ++dst) {
- *dst = *src;
- }
- return dst;
- }
- static vec_value_type _get_at(vector *pvec, int index) {
- return *(pvec->begin(pvec) + index);
- }
- static void _set_at(vector *pvec, int index, vec_value_type elem) {
- pvec->_start[index] = elem;
- }
- static vec_iterator _begin(vector *pvec) {
- return pvec->_start;
- }
- static vec_iterator _end(vector *pvec) {
- return pvec->_finish;
- }
- static vec_value_type _front(vector *pvec) {
- return *pvec->begin(pvec);
- }
- static vec_value_type _back(vector *pvec) {
- return *(pvec->end(pvec) - 1);
- }
- static int _size(vector *pvec) {
- return pvec->end(pvec) - pvec->begin(pvec);
- }
- static int _capacity(vector *pvec) {
- return pvec->_end_of_storage - pvec->begin(pvec);
- }
- static int _empty(vector *pvec) {
- return pvec->begin(pvec) == pvec->end(pvec);
- }
- static void _insert_n(vector *pvec, vec_iterator position, vec_size_type n, const vec_value_type elem) {
- vec_size_type old_size = 0;
- vec_size_type new_size = 0;
- int inset_index = 0;
- vec_iterator ite = NULL;
- assert(pvec->_start <= position && position <= pvec->end(pvec));
- CHECK_BORDER;
- if (0 == n) {
- return ;
- }
- inset_index = position - pvec->_start;
- old_size = pvec->size(pvec);
- new_size = old_size + n;
- // 先检查剩余空间是否足够,不够则扩容
- if ((vec_size_type)(pvec->_end_of_storage - pvec->_finish) < n) {
- const vec_size_type new_capacity = old_size + __max(old_size, n);
- vec_value_type *new_base = (vec_value_type *)realloc(pvec->_start, new_capacity * sizeof(vec_value_type));
- if (NULL == new_base) {
- exit(OVERFLOW); // 此时原来的空间将发生内存泄漏
- }
- pvec->_start = new_base;
- pvec->_end_of_storage = pvec->_start + new_capacity;
- }
- pvec->_finish = pvec->_start + new_size;
- position = pvec->_start + inset_index;
- // 移动元素
- for (ite = pvec->_finish; ite >= position + n; --ite) {
- *ite = *(ite - n);
- }
- // 插入n个新元素
- for (; ite >= position; --ite) {
- *ite = elem;
- }
- }
- static vec_iterator _earse_pos(vector *pvec, const vec_iterator position) {
- if (position + 1 != pvec->end(pvec)) {
- copy(position + 1, pvec->_finish, position);
- }
- --pvec->_finish;
- return position;
- }
- static vec_iterator _earse_int(vector *pvec, const vec_iterator first, const vec_iterator last) {
- vec_iterator i = copy(last, pvec->_finish, first);
- pvec->_finish -= last - first;
- return first;
- }
- static void _clear(vector *pvec) {
- pvec->earse_int(pvec, pvec->begin(pvec), pvec->end(pvec));
- }
- static void _push_back(vector *pvec, const vec_value_type elem) {
- CHECK_BORDER;
- _insert_n(pvec, pvec->end(pvec), 1, elem);
- }
- static void _pop_back(vector *pvec) {
- pvec->earse_pos(pvec, pvec->end(pvec) - 1);
- }
- static void set(vector *pvec) {
- pvec->_finish = NULL;
- pvec->_start = NULL;
- pvec->_end_of_storage = NULL;
- pvec->get_at = _get_at;
- pvec->set_at = _set_at;
- pvec->begin = _begin;
- pvec->end = _end;
- pvec->front = _front;
- pvec->back = _back;
- pvec->size = _size;
- pvec->capacity = _capacity;
- pvec->empty = _empty;
- pvec->insert_n = _insert_n;
- pvec->earse_pos = _earse_pos;
- pvec->earse_int = _earse_int;
- pvec->clear = _clear;
- pvec->push_back = _push_back;
- pvec->pop_back = _pop_back;
- }
- static void reset(vector *pvec) {
- pvec->_finish = NULL;
- pvec->_start = NULL;
- pvec->_end_of_storage = NULL;
- pvec->get_at = NULL;
- pvec->set_at = NULL;
- pvec->begin = NULL;
- pvec->end = NULL;
- pvec->front = NULL;
- pvec->back = NULL;
- pvec->size = NULL;
- pvec->capacity = NULL;
- pvec->empty = NULL;
- pvec->insert_n = NULL;
- pvec->earse_pos = NULL;
- pvec->earse_int = NULL;
- pvec->clear = NULL;
- pvec->push_back = NULL;
- pvec->pop_back = NULL;
- }
- void vec_construct(vector *pvec) {
- set(pvec);
- }
- void vec_construct_n(vector *pvec, const int size) {
- set(pvec);
- pvec->_start = (vec_iterator)malloc(size * sizeof(*pvec->_start));
- if (NULL == pvec->_start) {
- // TODO:
- exit(OVERFLOW);
- }
- pvec->_finish = pvec->_start + size;
- pvec->_end_of_storage = pvec->_finish;
- }
- void vec_destruct(vector *pvec) {
- free(pvec->_start);
- reset(pvec);
- }
3. 测试程序
- /********************************************************************
- created: 2013/08/19
- created: 19:8:2013 0:10
- file base: test
- file ext: c
- author: Justme0 (http://blog.csdn.net/Justme0)
- purpose: vector 的测试程序
- *********************************************************************/
- #include "vector.h"
- #include <stdio.h>
- void output(vector *pvec) {
- vec_iterator iter;
- for (iter = pvec->begin(pvec); iter != pvec->end(pvec); ++iter) {
- printf("%c\n", *iter);
- }
- }
- int main(int argc, char **argv) {
- char ch = 'A';
- int cnt = 5;
- vector my_vec;
- vec_construct(&my_vec);
- while (cnt--) {
- my_vec.push_back(&my_vec, ch++);
- }
- output(&my_vec);
- puts("set [2]: '2'");
- my_vec.set_at(&my_vec, 2, '2');
- output(&my_vec);
- my_vec.empty(&my_vec) ? puts("empty") : puts("not empty");
- puts("pop_back...");
- my_vec.pop_back(&my_vec);
- output(&my_vec);
- printf("size is %d\n", my_vec.size(&my_vec));
- printf("back is '%c'\n", my_vec.back(&my_vec));
- puts("clear...");
- my_vec.clear(&my_vec);
- my_vec.empty(&my_vec) ? puts("empty") : puts("not empty");
- vec_destruct(&my_vec);
- return 0;
- }
4. 运行结果
- A
- B
- C
- D
- E
- set [2]: '2'
- A
- B
- 2
- D
- E
- not empty
- pop_back...
- A
- B
- 2
- D
- size is 4
- back is 'D'
- clear...
- empty
- 请按任意键继续. . .
1、在测试程序中可以看到,定义一个结构体后,必须紧跟着用函数 construct 将对象的成员赋值以初始化,我称这个过程为“构造”。
2、最后必须显示调用 destruct 函数将对象“析构”,释放对象 malloc 的空间。
我将这个程序给某个 C++ 游戏程序员看,被他一阵批,说我的程序最大的缺点就是 不是面向对象;没有一个企业会让这份程序通过;“你写的是 Objective-C 形式”。桑心啊,我只好贴在这独自欣赏了。
C 语言中实现数据与方法的封装的更多相关文章
- 最简单删除SQL Server中所有数据的方法
最简单删除SQL Server中所有数据的方法 编写人:CC阿爸 2014-3-14 其实删除数据库中数据的方法并不复杂,为什么我还要多此一举呢,一是我这里介绍的是删除数据库的所有数据,因为数据之间 ...
- 关于VUE调用父实例($parent) 根实例 中的数据和方法
this.$parent或者 this.$root 在子组件中判断this.$parent获取的实例是不是父组件的实例 在子组件中console.log(this.$parent) 在父组件中con ...
- 使用JDBC从数据库中查询数据的方法
* ResultSet 结果集:封装了使用JDBC 进行查询的结果 * 1. 调用Statement 对象的 executeQuery(sql) 方法可以得到结果集 * 2. ResultSet 返回 ...
- Go语言中字符串的查找方法小结
这篇文章主要介绍了Go语言中字符串的查找方法小结,示例的main函数都是导入strings包然后使用其中的方法,需要的朋友可以参考下 1.func Contains(s, substr strin ...
- 返回数据中提取数据的方法(JSON数据取其中某一个值的方法)
返回数据中提取数据的方法 比如下面的案例是,取店铺名称 接口返回数据如下: {"Code":0,"Msg":"ok","Data& ...
- 【类库】私房干货.Net数据层方法的封装
[类库]私房干货.Net数据层方法的封装 作者:白宁超 时间:2016年3月5日22:51:47 摘要:继上篇<Oracle手边常用70则脚本知识汇总>文章的发表,引起很多朋友关注.便促使 ...
- C语言中强制数据类型转换(转)
原文地址不详 字符型变量的值实质上是一个8位的整数值,因此取值范围一般是-128-127,char型变量也可以加修饰符unsigned,则unsigned char 型变量的取值范围是0-255(有些 ...
- 最简单删除SQL Server中所有数据的方法(不用考虑表之间的约束条件,即主表与子表的关系)
其实删除数据库中数据的方法并不复杂,为什么我还要多此一举呢,一是我这里介绍的是删除数据库的所有数据,因为数据之间可能形成相互约束关系,删除操作可能陷入死循环,二是这里使用了微软未正式公开的sp_MSF ...
- C语言中字符数据的输入和输出
字符的输出 C语言中使用putchar函数来输出字符数据 #include <stdio.h> int main() { char a,b,c,d; //定义字符变量a,b,c,d a = ...
随机推荐
- IOS 判断设备类型
- (NSString*)deviceString { // 需要#import "sys/utsname.h" struct utsname systemInfo; uname( ...
- Java中遍历Map对象的方法
方法一: 在for-each循环中使用entries来遍历 这是最常见的遍历方式,在需要获取key和value时使用. Map<Integer, Integer> map = new Ha ...
- ORACLE 视图的 with check option
ORACLE 视图的 with check option 我们来看下面的例子: create or replace view testview as select empno,ename from e ...
- 线程:Exchanger同步工具
可以在对中对元素进行配对和交换的线程的同步点,类似于交易,A拿着钱到达指定地点,B拿着物品到达指定地点,相互交换,然后各自忙各自的事去了. package ch03; import java.util ...
- avalon2学习心得(1)
github上,avalon2的项目描述是这样的:“avalon2是一款基于虚拟DOM与属性劫持的 迷你. 易用. 高性能 的 前端MVVM框架, 适用于各种场景, 兼容各种古老刁钻浏览器, 吸收最新 ...
- const用法总结
1. const修饰变量 ; const int* a = &b; //情况1 int const* a = &b; //情况2 int* const a = &b; //情况 ...
- ArcGIS10.3.1于2015年6月发布
http://www.esrichina.com.cn/sectorapplication/ArcGIS%2010.3/index.html
- MFC之树控件
树控件对应的类: CTreeControl 树控件属性设置: 启用复选框:Check Boxes = True 父节点显示+-按钮:Has Button = True ; Lines At Roots ...
- YUI Array 之each| forEach(遍历)
1. yui-each原码: 遍历YArray.each = YArray.forEach = Lang._isNative(Native.forEach) ? function (array, fn ...
- struts2 0day漏洞
描述 Apache Struts2 近日出现一个0day漏洞,该漏洞在修补CVE-2014-0050和2014-0094两个安全漏洞处理不当,分别可以导致服务器受到拒绝服务攻击和被执行恶意代码. 漏洞 ...