在 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 语言中实现数据与方法的封装的更多相关文章

  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. qt model/view 架构基础介绍之QTreeWidget

    # -*- coding: utf-8 -*- # python:2.x #说明:QTreeWidget用于展示树型结构,也就是层次结构同前面说的 QListWidget 类似,这个类需要同另外一个辅 ...

  2. iOS开发- 界面传值(1)-通知模式(广播)

    之后的几篇博客, 记录下不同界面间传值的经常使用办法. 这篇文章记录广播的方式. iOS的设计模式中,通知模式也是当中重要的模式之中的一个,Notification直译为通知,事实上本人认为叫做广播模 ...

  3. 0..n去掉一个数,给你剩下的数,找出去掉的那个数

    转载请注明转自blog.csdn.net/souldak , 微博@evagle 首先,考虑没有去掉那些数,如果n是奇数,n+1个最低位肯定是0101...01,count(0)=count(1),如 ...

  4. NSSCanner 提取 指定 字符串

    /** *  从msg中提取指定的内容 * *  @param msg 字符串集合 * *  @return 从msg中提取指定的内容 */ -(NSString*)extractBodyFromMe ...

  5. phpStudy + JspStudy 2014.10.02 下载

    phpStudy + JspStudy 2014.10.02 下载 目标:让天下没有难配的php环境. phpStudy Linux版&Win版同步上线 支持Apache/Nginx/Teng ...

  6. HTML与CSS入门——第三章 理解HTML和XHTML的关系

    知识点: 1.以HTML创建一个简单网页的方法 2.包含每个网页必须有的所有HTML标签的方法 3.用段落和换行组织页面的方法 4.用标题组织内容的方法 5.HTML.XML.XHTML和HTML5之 ...

  7. 改进的简单Tooltips显示

    使用js简单改进了Tooltips的显示效果,可进一步使用CSS对改进的Tooltips进行美化. 前台布局代码: <asp:Panel ID="Panel1" runat= ...

  8. XtraReport改变纸张方向

    XtraReport纸张方向改变可以通过修改Landscape属性: Landscape=true 为横向输出 Landscape=false 为纵向输出

  9. UITableView总忘记的

    因为总是忘记所以记一下 1.scrollToRowAtIndexPath QQ会话中总是希望添加一行就向上滚动总是显示最新的消息 NSIndexPath *lastIndexPath = [NSInd ...

  10. QT皮肤框架-TQUI

    本皮肤框架的相关文档,请在附件中下载,包括测试程序源码,帮助文档.相关文档可到我的百度网盘中下载,或者在本贴附件中下载. 百度网盘地址:TQUI-V1.0项目说明及测试程序源码 项目更新说明:---- ...