注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

天地不仁,以万物为Googol!

天行有常,不以物喜,不以己悲……

 
 
 

日志

 
 

关于封装的进一步理解  

2005-10-15 17:30:24|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
首先一点是数据绑定。
 
比如字符串,c风格的字符串函数,大家熟悉的有sprintf,strcpy,strcmp,strcat等,实际上,在c的库中,以上函数都还有另一个版本:snprintf,strncpy,strncmp,strncat等,这些带n修饰的函数与之前的唯一区别就是:多了一个标识目标指针最大长度的参数int n。为什么要有这个参数?因为c风格的字符串实际只是一个char*指向的数组而已,使用字符串时,必须由调用者判断指针是否超过申请的内存长度,也就是常说的内存越界。由于使用char*时无法判断之前申请的内存长度,因此sprintf等函数有可能会产生读写越界的情况,也因此,为了安全性,出现了snprintf之类的函数,在调用时通过传入int说明目标内存的分配长度,这样就可以保证不会越界。当然如果你传的int比你实际分配的内存还要大的话……
 
这个问题的实际原因在于,c风格字符串本身并没有保存自身分配内存的信息。为了克服这个缺点,我曾经见过有的c程序员声明这样的结构:
 
struct MyString
{
    int len;
    char* data;
};
 
#define ALLOC_STR(_str, _len) {(_str).len = (_len);(_str).data = malloc(sizeof(char) * (_len));}
 
这样,使用的时候就可以:snprintf(str.data, str.len, ...);
 
注意!已经有封装的思想在里面了!将string的两个特性:string的内容与string的长度绑定在了一个结构里面,这样在取用的时候,不会找错对应关系。而如果sprintf等函数以MyString结构做参数传入,就可以方便的检测到这个MyString可用的最大长度。
 
而封装,一个最大的特性,正是为了将与某个事务有关的属性,方法等特征绑定在一起。
 
第二点,便是隐藏细节,上一篇blog已经提及,这里再大概说一下。
 
对字符串的写入越界,一个原因是因为sprintf知道字符串的具体实现方式是字符数组,因此就按照数组的方式写入。如果字符串的写入方式只能通过某个特定函数完成呢?这个函数中会通过绑定的数据得到字符数组可用的最大空间,写入的时候会保证不会越界,那么,这个问题也就解决了。
 
ok,只通过函数完成某个任务,正是封装中隐藏细节的手法,还是字符串类:
 
class MyString
{
public:
    assign(const MyString& data);
private:
    int _len;
    char* _data;
}
 
这样,如果想对MyString的实例赋值,则只能通过assign函数完成。在assign函数中会自动完成越界判断,写入数据等功能,甚至,当原有的空间不够时,assign可以自动分配新的空间,来容纳更长的数据。
 
更进一步,如果我觉得用数组维护的方式不爽,会经常发生内存重新分配的情况,打算改用链表的方式存放。这时,我只要保证assign函数的声明方式不变,对其他程序来讲,使用上与改之前就没有任何的不同:
 
class MyString
{
public:
    assign(const MyString& str);
private:
    int _len;
    struct DataStruct
    {
        char* _data;
        DataStruct* _pNext;
    }
}
 
用户可以看到的部分(public的部分)没有任何变化,因此,使用上也没有变化。我改变字符串的实现方式后,只要把整个工程重新编译一遍,就可以完成这个改变了。
 
当然,这个只是封装的思想。至于一个类封装的是否成功,那就要看程序员的功力了。
  评论这张
 
阅读(226)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017