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

为着理想勇敢前进

 
 
 

日志

 
 

我最近的 C++ 编码风格   

2007-12-12 15:46:42|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
本文最早是在 Linus 炮轰 C++ 事件以后写下的。当时痛定思痛,对 C++ 一下子有了一个不同的认识。当时写出来这些文字但没有公开,这两个月对这种务实编码风格有了一些实践经验,可以把这篇文章修改修改公布出来了。

自从我接触 boost 以来,我的编码习惯就模仿 boost ,其实那样并不是最好的。 boost 对 C++ 的语言特性的使用没有限制,支持大量的不同的编译器
,并且为了这些编译器能在一起工作做了许多别的事情。我没必要支持所有的 C++ 语言特性,也没必要支持所有的编译器。所以我应该有一个不同的编码规范。

1 原则
1.1 封装性
这对我来说不是问题,我早已养成了这个习惯。但是,我必须得把这一条原则写在前面,否则,光看到第二条的读者就会被我误导。
1.2 大胆的硬编码
在模块内部,只要有利于减少代码量,什么手段都可以用!把 C++ 看成比 C 更低级的语言,这样,使用 C++ 的奇技淫巧就不会有心理负担。我认为,增加代码可读性的最有效方法就是减少代码量。
2 C++ 的特性使用
C++ 的特性,大概可以分成4类。低级特性、高级特性、语法糖、没用的特性。
2.1 低级特性
模板属于低级特性。模板以及 boost 中相关的支持,都属于低级特性,比 C 语言更低级的特性。
模板的使用有两种情况:
a) 小的实用工具库,这种实用工具库应该是相对独立的,与其他数据结构不应该有什么关系。要求模板的代码必须尽量简洁。
b) 在 cpp 文件内部用模板来提高效率和减少重复代码。这种方式使用的时候,只是一种复用小规模代码的语法糖,不应暴露在头文件中。
2.2 高级特性
虚函数就是这样一个高级特性。纯虚类用来做 handler 很好。此外,如果真的需要多态的话,也可以用虚函数。
要指出的是,只有真正需要多态才用虚函数,而这种需求其实并不普遍。滥用虚函数最常见的一个借口就是灵活性。大多数时候灵活性都不是需求,而仅仅是因为虚函数能够多态因而那个程序员幻想出来有这样一个需求。
2.3 语法糖
继承、static_cast、reinterpret_cast、运算符重载、函数重载、命名空间、成员函数、类静态成员,这些都是语法糖。我对语法糖没什么意见,能用就用。当然我们知道语法糖很容易被滥用,但我觉得其实只要接口简洁,滥用也滥不到哪里去。这些语法糖的使用应该主要是实现层次的,尽量不要出现在头文件中。
2.4 没用的特性
2.4.1 引用
我受够了!左值/右值、复制引用/复制值 这些问题已经折磨了我很长时间了。我想,如果要用指针就用指针,不用遮遮掩掩说那是一个引用。如果 boost 不需要支持引用的话,我估计 boost 里面跟模板相关的代码可以减少三分之一。我今天决定了,以后除非调用别人的函数要求传引用,否则我绝对不在自己的代码里面用引用。
2.4.2 private 、 public 和 class
任何暴露在头文件中的东西,都理所当然是 public 的。而需要隐藏的实现,如果有办法隐藏,自然可以放到 cpp 文件中。用 C 的那些办法来隐藏实现,比用自欺欺人的 private 好多了。我们知道 class 和 struct 在 C++ 中的唯一区别就是 class 默认成员为 private ,由于 private 是自欺欺人的,所以我们在一切地方都用 struct 代替 class
2.4.3 dynamic_cast和typeid
使用多态的唯一正确方式就是用虚函数,正确编码的代码一定可以避免 dynamic_cast 。
3 关于模块
3.1 一个模块就是一个 cpp 文件,最小几十行代码,最大不超过1000行。函数分为两类。一类是出现在头文件中的接口,另一类是模块内部用的,仅仅用来避免重复代码。
3.2 头文件。直接暴露数据结构就是编写良好接口的捷径!试图隐藏实现是愚蠢的。此外,接口函数应该以自由函数为主,但也可以使用成员函数。对于需要严格分离的接口,可以使用纯虚类,纯虚函数来定义。
3.3 组织模块内部编码时,唯一的目标就是代码最短,避免任何包装开销。内部不必是良好定义的,不必是正交的,为了减少代码,甚至可以大量的使用宏。同时,把模板当成一种低级特性来用,只要有利于简短代码量,一切奇技淫巧都可以用。
4 模块接口的参数传递
4.1 缓冲区和字符串
对于接受字符串的函数,接受的参数是首地址指针和长度,或者首末地址也可以。当然,字符串和缓冲区的具体存储字段,可以用 std::vector<char>
4.2 时间
不使用任何 C++ 类,一律传整数,比如 time_t 或者其他自定义的整数 。强大的 Boost.Date_Time 可以拜拜了。
4.3 指针
一切想要传引用的地方,都明白无误的传指针。
4.4 模板参数
因为已经规定了不使用引用,模板参数就可以不必考虑引用,每一个参数都可以传值。类似这样:template<typename T0, typename T1> void func(T0 t0, T1 t1);
  评论这张
 
阅读(708)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

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

页脚

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