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

天地不仁,以万物为Googol!

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

 
 
 

日志

 
 

c++的表现,c的实现

2006-09-17 10:53:30|  分类: 积累 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

工作第一周,除了学学文档,实在没啥可做的,于是自己研究写了点东西。记录下来。

 

c的优点是灵活,但是太灵活了,如果在多人合作时,c程序会给对方暴露过多的内部实现细节,比如对方可以直接访问全局变量之类。而c++则正是为了弥补这个缺点而实现的。当然,后期c++加入了更多的程序设计思想,比如泛型,但这个有机会再讨论。

 

比如,c中为了实现一个协议,经常定义如下的结构体:

struct SomeProtocolStruct

{

  Protocol head_;

  uint length_;

  uint8 data_[1];

};

 

最后的那个data[1]很诡异不是么?实际这是利用c在struct内存里的布局,来实现可变长度数组的一个技巧。(这个技巧已经被c99明确说明不建议使用,但c++还没见这个说法,包括tr1里也没有提到)使用时可以:

SomeProtocolStruct* protocol = malloc(sizeof(*protocol ) + length - 1);

protocol->length_ = length;

/* use protocol->data_ as a data_[length] */

 

但是这里一个缺点是,使用SomeProtocol时,没有任何措施可以保证使用者对其读写是正确的,比如,无法阻止用户对data_[length +n]的访问。

 

为了解决这个问题,可以利用c++对这个结构进行封装,同时,在给对方的接口中,只有这个封装类的定义,其余部分可以编译成lib,或者放在另外的地方进行联编。这个封装简略如下:

 

class SomeProtocol

{

public:

  SomeProtocol(uint length);

  SomeProtocol(SomeProtocol& arg);

  ~SomeProtocol();

  void operator=(SomeProtocol& arg);

  uint getLength() const;

  void setData(uint index, uint8 data);

  uint8 getData(uint index) const;

  void setDataBlock(uint index, uint8* p, uint length);

  const uint8* getDataBlock(uint index,/* length? maybe future. */) const;//return type is const uint8 *, to forbid to change the data

 

private:

  SomeProtocolStruct* protocol_;

};

 

这样,所有对protocol_的操作,都要通过SomeProtocol类的方法来实现。这样,对data的访问就处在SomeProtocol类的控制之下,即可以使用这种技巧,又可以保证使用者操作的正确。再进一步,还可以将uint8*和uint联合表示的一段内存做封装,进一步增加使用的安全性。这样,也可以更好的防止getDataBlock对内存的暴露。(比如,c++ tr1里描述的array类,就是一个对定长数组很好的封装实现。那个类同时展示了模版的强大!见:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1479.html

 

进一步研究:

 

加入泛型后,SomeProtocolStruct可以写为:

template <int Length>

struct SomeProtocolStruct

{

  Protocol head_;

  uint length_;//to protocol, still need this value

  uint8 data_[Length];

};

 

这样可以避免c的那种近似hack的技巧。为了进一步明确泛型的用处,我们需要缩小泛型的层次,将其降低到更底层:

template <typename Type, int Length>

struct RawArray

{

  Type data_[Length];

};

 

template <int Length>

struct SomeProtocolStruct

{

  Protocol head_;

  uint length_;//to protocol, still need this value

  RawArray<uint8, Length> data_;

};

 

之后的封装类需要使用一些技巧,以免对每个长度的SomeProtocolStruct都产生一段大体相似的代码:

template <int Length>

class Protocol

{

public:

  template <int L>

  setDataBlock(uint index, RawArray<uint8, L> data)//for example. And data will automaticly deduce by compiler

  {

     someProtocol_SetDataBlock(data.data_, protocol_->data_ + index, L);

  }// this function should be expand if the compiler support inline, and ti will dispatch all template function to a non-template function. That non-template function is one and only in the compiled file

 

private:

  SomeProtocolStruct<Length>* protocol_;

}

 

someProtocol_SetDataBlock(uint8* src, uint8* dst, uint len)//the define is in another file

{

  memcpy(src, dst, len);

}

  评论这张
 
阅读(440)| 评论(0)
推荐 转载

历史上的今天

评论

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

页脚

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