C语言结构封装一法

原文载自:http://www.limodev.cn/blog/archives/278

 

(个人觉得封装蛮有特色的,或者自己刚开始关注这个吧,所以就将其有意思的一段摘录于下。其实,我还是有点赞成文中隐藏数据结构的做法:(1)在头文件中声明该数据结构 (2)在C文件中定义该数据结构)

 

 

隐藏数据结构

暴露内部数据结构,会使头文件看起来杂乱无章,让调用者发蒙。其次是如果调用者图方便,直接访问这些数据结构的成员,会造成模块之间紧密耦合,给以后的修改带来困难。隐藏数据结构的方法很简单,如果是内部数据结构,外面完全不会引用,则直接放在C文件中就好了,千万不要放在头文件里。如果该数据结构在内外都要使用,则可以对外暴露结构的名字,而封装结构的实现细节,做法如下:

在头文件中声明该数据结构。

如:
struct _LrcPool;
typedef struct _LrcPool LrcPool;

在C文件中定义该数据结构。

struct _LrcPool
{
    size_t unit_size;
    size_t n_prealloc_units;
};

提供操作该数据结构的函数,哪怕只是存取数据结构的成员,也要包装成相应的函数。

如:
void* lrc_pool_alloc(LrcPool* thiz);
void lrc_pool_free(LrcPool* thiz, void* p);

提供创建和销毁函数。因为只是暴露了结构的名字,编译器不知道它的大小(所占内存空间),外部可以访问结构的指针(指针的大小的固定的),但不能直接声明结构的变量,所以有必要提供创建和销毁函数。

如:
这样是非法的:LrcPool lrc_pool;
应该对外提供创建和销毁函数。
LrcPool* lrc_pool_new(size_t unit_size, size_t n_prealloc_units);
void lrc_pool_destroy(LrcPool* thiz);

任何规则都有例外。有些数据结构纯粹是社交型的,为了提高性能和方便起见,常常不需要对它们进行封装,比如点(Point)和矩形(Rect)等。当然封装也不是坏事,MFC就对它们作了封装,是否需要封装要根据具体情况而定。

隐藏内部函数

内部函数通常实现一些特定的算法(如果具有通用性,应该放到一个公共函数库里),对调用者没有多大用处,但它的暴露会干扰调用者的思路,让系统看起来比实际的复杂。函数名也会污染全局名字空间,造成重名问题。它还会诱导调用者绕过正规接口走捷径,造成不必要的耦合。隐藏内部函数的做法很简单:

在头文件中,只放最小接口函数的声明。

在C文件上,所有内部函数都加上static关键字。

禁止全局变量

除了为使用单件模式(只允许一个实例存在)的情况外,任何时候都要禁止使用全局变量。这一点我反复的强调,但发现初学者还是屡禁不止,为了贪图方便而使用全局变量。请读者从现在开始就记住这一准则。

全局变量始终都会占用内存空间,共享库的全局变量是按页分配的,那怕只有一个字节的全局变量也占用一个page,所以这会造成不必要空间浪费。全局变量也会给程序并发造成困难,想把程序从单线程改为多线程将会遇到麻烦。重要的是,如果调用者直接访问这些全局变量,会造成调用者和实现者之间的耦合。

在整个系统程序员成长计划中,我们都是以面向对象的方式来设计和实现的(封装就是面向对象的主要特点之一)。为了避免不必要的概念混淆,这里先解释一下对象和类:

关于对象:对象就是某一具体的事物,比如一个苹果, 一台电脑都是一个对象。每个对象都是唯一的实例,两个苹果,无论它们的外观有多么相像,内部成分有多么相似,两个苹果毕竟是两个苹果,它们是两个不同的对象。对象可以是一个实物,也可以是一个概念,比如一个苹果对象是实物,而一项政策就是一个概念。在软件中,对象是一个运行时概念,它只存在于运行环境中,比如:代码中并不存在窗口对象这样的东西,要创建一个窗口对象一定要运行起来才行。

关于类:对象可能是一个无穷的集合,用枚举的方式来表示对象集合不太现实。抽象出对象的特征和功能,按此标准将对象进行分类,这就引入类的概念。类就是一类事物的统称,类实际上就是一个分类的标准,符合这个分类标准的对象都属于这个类。当然,为了方便起见,通常只需要抽取那些对当前应用来说是有用的特征和功能。

 

(后记:

 

其实可以通过编译宏来区分一下

/*******************公有结构和变量************************************/
#ifdef USE_CLASS_PUBLIC

struct _Class_A;
typedef struct _Class_A CLASS_A;
typedef struct CLASS_A *  P_CLASS_A;

#endif

/*******************私有结构和变量************************************/
#ifdef USE_CLASS_PRIVATE

struct _Class_A
{
    int  a;
    char c;
};

#endif

这样结构都定义在头文件中,需要看到结构的,和不需要看到结构的,可以通过不同的编译宏来区分,而不需要多处定义结构,或者将一些原本简单的应用复杂化。面向对象固然好,但对于一些应用来说,C的简单灵活,确实是首选之选。

 

 

)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值