今天从图书馆借了本Herb Sutter的《Exceptional C++ Style》,Herb在这本书的最后专门整了个专题来讨论std::string的设计问题,其中的核心内容就是讨论给std::string瘦身,更进一步,Herb提出了他的观点--“为了避免巨型(monolithic)设计,尽可能编写非成员非友元形式的函数”。
Herb认为如果一个class总是试图通过成员函数而不是非成员函数来提供功能 ,将会有两个主要的问题:
- (主要问题)把可能独立可用的功能"封锁"在了一个类的内部
- (次要问题)这种设计可能会阻碍你为一个类扩展出新功能
不过根据自己实际使用中的一点感受,我恐怕还就是更趋向于成员函数。o,慢点,没搞错吧?是的,我的理由其实很简单,因为对于一个member function,几乎的所有的IDE都支持一个看似简单,但是非常有效的小trick--智能感知(intelli-sense)。然而对于C++中的一个非成员的函数,IDE是无能为力的。看看STL里面有那么多的标准用法,但实际当中很多人却还要去重复实现自己的版本,恐怕也有这方面的原因。毕竟容器就那么几个,了解一下也许还不是太费劲,但是各种算法、操作数量就太多了,要想一一了解还真不是那么容易
一个Class里面涉及到的相关操作可能很多(像std::string就有超过一百个的成员函数),要清楚的了解所涉及的所有操作实在是很难。诚然,作为一个勤劳的程序员,你也许会说这不是问题,document就安静的躺在你的硬盘上,再加上无所不能的Google,理论上完全可以掌握所有的操作,不管是成员函数还是非成员函数。但是有一点可以肯定,如果这个函数是成员函数,用起来恐怕要爽的多--首先有IDE的智能感知的支持,如果不会用,ok,在文档里面很轻松的就可以找到详尽的描述。而如果是非成员的,那就糟糕了,三找两找都找不到,要知道程序员也有急躁的时候,好吧,干脆放弃搜索行动,就一个函数嘛,我自己也能实现的...但事实往往不那么简单:(
回到Herb的讨论中,是Herb错了吗?当然不是,他的两个观点都是很有道理的。那是我们错了吗,好像也很难这么讲,IDE确实对这种非成员函数无能为力呀!作为一个coder,我就不能有一点小小的要求吗?
那么我们现在就来YY以下,有没有可能为C++的IDE增加这种支持非成员函数与对象邦定的intelli sense功能?完全可以,在这个问题上,C# 3.0已经给C++作了一个很好的典范。为了支持LINQ技术,Anders为C#引入了Extension Methods,如下面代码:
namespace System.Query
{
public static class Sequence
{
public static IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate) { … }
public static IEnumerable<S> Select<T, S>(this IEnumerable<T> source, Func<T, S> selector) { … }
// more functions
}
}
在调用的程序里,只要导入System.Query的namespace,对于实现了IEnumerable接口的对象,就可以像成员函数一样使用Sequence里面的这些Select, Where...方法了,而且都是带有智能感知功能的哟,ok,Extension Methods,就是这样。至于底下具体的转换工作,那是编译器的事,我们就不管了。
实际上C++完全可以提供类似概念的extension methods,同样运用namespace的概念,似乎我们就可以将Herb大师分析出来的std::string中的那些非成员函数放到一个namespace下,然后将这个namespace添加到std::string或者是调用端的文件里面,根据IDE的自动推断,用户使用的时候感觉就和成员函数一样方便,只要知道std::string就可以找到想要的方法,智能感知当然也是可以提供的。而且这些方法本身还是非成员函数,代码仍然可以被不同单元reuse。当然,修改一下编译器还是必要的,毕竟这个翻译过程还得由编译器来替我们做。
貌似这样既到达了Herb大师追求高质量设计的目的,又给我们这些懒惰的程序员提供了实际需要,perfect!
嘿嘿,全当自己YY吧:)