曾几何时,学会了C语言。安装了VC6这个神叉IDE。
然后被迫开始CPP路程。由于C++兼容C,所以一直在以C的方式写C++。然后慢慢的开始学写C++代码。写C++代码是从MFC开始的。慢慢的,我学会了用class,感觉是个比struct好用的多的结构体。再慢慢的,我学会了继承,还有… 多重继承。
MFC 就是我的导师。开始不停的向MFC学习。既然用了c++的继承,就认识到了继承的陷阱。继承后,构造函数和构析函数的执行次序,等等。还有虚继承后的各种问题和陷阱。
一一去了解。
在程序结构方面,开始向 MFC 看齐。喜欢把任何操作都包装到class里。设计class的时候,开始过度设计。总考虑到某天我会需要继承它。说不定还需要多重继承。等等。明明已经设计好class,却喜欢继续添加功能。永远用不到的功能。只因为我“未来可能需要在别的程序里用,可能需要继承它。”
任何一个程序,我都为它设计对象,全局的程序对象又有子对象,子又有子,子子孙孙无穷尽也~
成员变量一多,构造函数里成员变量初始化代码就变多。然后设计构造函数重载。写更多的用不到的构造函数。 我没有意识到,我已经犯了过度设计的毛病了
而c++另一个强大的功能“模板”我却一无所知。当我发现了c++还有模板功能的时候,我只是简单的尝试了一下,发现模板无法在VC下很好的被自动完成。又听说模板会导致代码膨胀,诸如此类。我只小用一下模板。就丢弃了模板。继续我过度设计的c++之路。
某一天,我开始Linux之路。当我开始写出第一个GTK程序的时候,发现了C之美。C可以写出和C++一样的对象代码。而且没有了 C++的许多陷阱。
也正因为C,我开始摒弃了过度设计。所设计的API皆以现阶段够用为限。未来怎么样,未来再添加好了。没有了c++的包袱,再也不设计class了。都是简单的函数。函数完成一个“过程”。而不再是操作一个“对象”。让我把精力放到了“过程”本身,而不会再去设计“漂亮的对象”。
之后阅读到了Linus对C++的一篇讽刺邮件。对比自身,多多感触。c++确实是个容易写出糟糕代码的语言。
从此发誓不再用c++,只以C写代码。
再一次拾起C++,是因为c++11的发布,有了一些新的语法糖。我虽然不再打算写c++代码,但是没打算不再读别人的c++代码。如果别人用c++11写了新的代码,我确看不懂,不是损失是什么。我决定看一看c++11。
c++11最令我着迷的新特性就是lambda。还有新的for语法。当然,boost::bind 和 boost::function 进入了 std。成为的标准的一部分。我对 std::function 的印象只限于“更好的函数指针替代”。
lambda 一用,发现非常不错。好多麻烦的 static 函数都可以被匿名的 lambda取代了。我喜欢这种让名称空间更干净的感觉。
我开始纠结lambda了。动摇了。如果只用c++兼容C的那部分,然后lambda,就是带lambda的C嘛!这样自欺欺人的开始用C++。
参与了朋友的一个小项目。他是个重度c++粉。但是因为他的关系,我开始真正的拿起了boost。他说,没有boost他就没办法写代码。
这里有个小插曲,我在Linux下一直用eclipse编程,但是也因为boost把eclipse搞崩溃了,重拾了KDevelop。结果发现KDevelop已经不再是我第一次使用的时候(Kdevelop 3.? 的样子,好多年前的尝试。)那样使用正则匹配的自动完成了,真正的和eclipse一样是通过语法解析获得的自动完成列表。这导致KDevelop的自动完成功能异常强大,和 eclipse一样智能。所不同的是,eclipse在解析boost的代码的时候会时不时的崩溃,而且eclipse花了很久很久的假死状态解析boost头文件。毕竟是java开发的,速度还是不行啊!但是KDevelop完成boost头文件的解析只需要几秒钟。第一次打开cpp文件的时候,KDevelop在后台花了及秒钟解析了boost头文件,然后打代码的时候boost的所有功能就全部都能提示出来了。和eclipse一样的自动完成,速度快了几百倍,我马上切换到了KDevelop,并卸载了eclipse。
其实之前也尝试过boost,都被假死状态的eclipse弄怕了。所以关了eclipse的index功能没了boost的语法提升瞎写过。
但是换到KDevelop后那畅快淋淋的感觉,打出 boost:: 后那完善的提示,我马上开始全身心的试用boost。
就是这一试用,让我重回了c++的怀抱。重回c++后,我发现了c++正确的用法:
class只能作为基础,构建比int/long/char要高级点的对象。绝不能用来构造程序本身。像MFC那样搞个 CMyApp 绝对是对c++的侮辱。也就是说,程序主体仍是C语言式的。
可以用class构建string,构建bigint,用重载为bigint编写大数乘法... 这才是 class 和运算符重载的意义。绝对不能肆意滥用。
必要的时候编写模板代替宏。
模板更好的用法是使用boost这样现成的模板库。
设计回调函数,使用 std::function/boost::function。这样可以使用 std::bind/boost::bind 绑定任意多的参数给回调函数用,避免C里的void*user_data设计。
虚回调函数绝对是个傻逼设计。迫使用户使用继承并进行虚成员函数重载。