[C++语法语义探讨] C++最重要的语法-const, private

qiezi 2007-06-10
公司有个同事也是使用C++开发,代码质量从我个人角度来看感觉非常差,几个明显地方:

1、类、对象的概念非常混乱,某些类只能生成一个对象,多了肯定有问题了。这导致无法在一个进程中监听多个端口,当然人家的解决办法就是用多进程。

2、类与类之间强耦合,可以说除了一些小工具类以外,没有任何一个类可以单独拿出来使用,所有类里面的成员都是public,因为你不知道哪个其它类还要使用这个成员。线程函数因为要访问对象的成员,所以类也是全public,我实在看不过去了,把线程成员改成private,线程函数加上friend了,也被批为语法太花梢。。。当然也就不可能搞什么单元测试了,整个程序都是写好了编译好,连上数据库运行,再写个TCP或UDP的客户端来测试。。倒是很黑盒。。。。

3、BIG THREE显然完全不知道是什么东西。不能拷贝的东西把拷贝构造函数和operator=给private掉亚。

4、由于对C++以及STL的不熟悉,导致根本不敢用STL。问过原因,说是内存卸漏,我猜是因为string的COW吧,多个线程共享string时拷贝可能会有问题,本来只需要禁止掉这些拷贝就行了,他的解决办法是自己写一个string,内部是一个大的数组,当然一些潜在的拷贝成本人家也不考虑了,这个数组只有构造函数和2个public成员,要用字符串方法?找str*吧。。。

5、所有接口参数用的都是char*而不是const char*,所有不修改内部状态的方法都没有加上const。结果我在使用这些方法时不得不加上const_cast<char*>(str.c_str())。。。人家还说我的用法太丑了,郁闷不?也不好意思说。

6、跨平台就跨平台吧,用点宏无所库。不过别滥用嘛,长连接短连接也用一个宏分别编译,结果是一个进程中无法同时存在一个长连接和一个短连接。。。

7、代码风格。说不上是C还是C++还是其它风格,反正是混合体。

8、TCP接收写得很糙,收一下就结束,当然数据比较少还是可以用的。

9、所有工具类的封装都让我感觉别扭,比如一个TcpListener类只有一个listen和accept方法,封装的唯一原因是把一些参数设置加进去,accept完成一些连接的IP限制、连接的超时设置等功能,当然由于他的风格,这些功能也是从一个全局的g_pApp读取参数。。。。顺便说一下,这个g_pApp在各个类中都要用到的,它是所有对象的集合,这个大的蜘蛛网以它为中心。。。

10、锁成本不计。观点是不要锁的太久,否则影响其它线程。于是代码写成这样:
int threadFlags[THREAD_COUNT];
// ......
for(int i=0; i<THREAD_COUNT; i++)
{
    lock();
    if (threadFlags[i] == 0)
        ......
    unlock();
}


11、死代码、废代码、无用注释随处可见。死代码指的是硬编码,上面说的长连接短连接不同共存本身也是硬编码;配置文件也被硬编码了,换一种配置文件西式,很多代码要重写;策略的东西也被硬编码,因为一些策略就是写在配置文件中的。废代码指的是根本用不到的代码,由于上面的一些原因,某些代码不能从项目中拿掉,所以他现在的复用方式就是把一个旧项目拷贝一份去修改。无用注释也很多,主要是一段代码可能在某个项目中有用,在另一个项目中无用,于是注释掉,以防再拷给下个项目使用时可能又用到这段代码。。


以上摘录一些主要特征,大致水平层次应该都很容易看明白。我也尝试过提供一些类给他使用,被拒绝了,之前也有同事提供库被拒绝。人家还很自负,资格年龄都比我大,围棋方面还拿过大运会冠军,所以智商方面也不容质疑,在公司也有很大贡献,当然也不好说什么了,有时候折衷一下,自己的项目使用自己的代码就是了。

除了编程思路和基本功以外,一些东西我觉得可以用语法限制来改善。C/C++中我觉得最重要的是const,因为不管有没有类存在,它都是要考虑的。第二重要的应该是访问级别了,它会影响到对象之间的关系。这些限制如果让你觉得障碍重重,就得检查一下自己编写的代码了。

以上当是发个劳骚吧,这种情况以前呆过的小公司还没遇到过,就算是刚毕业也不至于把代码写成这样。

另一个劳骚是通过我参与的项目发现,一些经常加班甚至长期通宵的,可能不是工作量的问题而是能力问题,经常可以看到一个小东西都能折腾他几小时,影响整个项目进度,当然人家也长期受公司表彰的。
wzgme 2007-06-11
建议公司把复用代码提升到内部开发库上啊,强制使用。做详细设计的人,难道就没有沟通和限制吗?
这位老兄是核心开发,让他做C吧。接口参数都不用const,还真是胆大啊。
你们是怎么分工,怎么集成代码的啊,感觉很松散的。不过也真的不好控制。
我现在是提供数据操作、和图形绘制的微平台+核心科学算法库,再规定一些纯虚接口,具体模块类的实现,各人折腾吧,水平不同,习惯不同,C++的风格真的很难控制。

C++的GUI,完全的界面无关,自由的界面布局,对交互式程序真的很头痛。就像开发WEB一样开发桌面程序,自由的用Xhtml+CSS控制界面布局,随意的更改表现层,不知道现在有这样的东西没啊。
qiezi 2007-06-11
目前的項目都比較小,說實話我以前還沒做過這麽小的項目,不過感覺大點的互聯網公司都在做小項目。目前是每人負責一個小項目,最多帶一個做PHP的搞一下協議接口,所以寫再差也能完成。

你說的GUI,我感覺用xul就可以。
bigpanda 2007-06-11
呵呵,我还以为qiezi写了什么const的总结篇呢,原来是牢骚篇。

在哪里都有这样的人,别发牢骚了,发也没用,还短寿。

十全十美的事情是没有的,自己挑的老婆还得磨合,何况是一头跳进去的公司的同事。

关于wzgme问的,我也觉得就xul行,微软的WPF现在还不跨平台,而且也该用C#。

xul的设计,颇受COM的影响,以前有点COM的底子上手挺快的。
wzgme 2007-06-11
XUL,以前不是很了解,不知道能和OpenGL等集成不?

qiezi 2007-06-14
劳骚完了,好像也有点改观。

这几天一个C++中间件集群项目,要连接8台数据库服务器,每台又有几百个库,每个库几百张表。我先把功能实现了,再处理读取配置文件的代码,同事是写在一块了,而且多处代码涉及到读取配置。结果当然很明了,我可以提早完成,而且中间一个需求变化,配置文件大修改,我10分钟修改完成,同事改了一天还加班。这个结果是可以预料的,我也想找这样的机会震动一下他。

一点点变化是他也开始看我的代码了,有时候还会问为什么用const T&而不是T,为什么是const_iterator而不是iterator,为什么成员函数要加const,虽然很基础。当然起因也是我把他的一个类加了大量const而对他的代码没什么影响,当然我的代码里大量丑陋的const_cast可以删除掉了。

我之前的项目基本上逻辑部分依赖于单元测试,接口部分则依赖于语法检查,通常单元测试过了以后,编译没问题上线跑问题也不大,架构清晰就行。同事基本上不写单元测试,结果是写完代码之后据他说要认真地看上20-30遍,完全把自已当编译器使了。

并不是真的要劳骚,而且同事也不看这里,主要是给初学者一点提示,代码别写的乱糟糟的。

补充一点个人以为的重要原则:尽量别使用全局变量甚至是单件(和全局变量差不多)。如果代码消除了全局变量,肯定会清晰不少,MFC的theApp是个反面教材,但人家写得也还算清晰,不至于到处要用到theApp.vara, theApp.varb.
qiezi 2007-06-14
wzgme 写道
XUL,以前不是很了解,不知道能和OpenGL等集成不?


应该是可以的,当然我没做过。已经有使用xulrunner开发的播放器,它会创建一个原生窗口,否则没办法放播放器窗口,你的opengl应用大概也只需要一个窗口就行了吧。
wzgme 2007-06-14
我是要在OpenGL里做3维图形显示交互。
目前我用QT4。
其实我的想法和XUL还是有距离的,XUL是RichClient,而我想要的是完全的本地。
RyanPoy 2007-06-14
qiezi 写道
劳骚完了,好像也有点改观。


我之前的项目基本上逻辑部分依赖于单元测试,接口部分则依赖于语法检查,通常单元测试过了以后,编译没问题上线跑问题也不大,架构清晰就行。同事基本上不写单元测试,结果是写完代码之后据他说要认真地看上20-30遍,完全把自已当编译器使了。



想问问,你的单元测试是怎么个测法。又没有借助什么测试工具。还是自己写main方法进行测试。我发现我现在的做法,有点像你的同事了。一般是一个功能块完全写完了后再测试。现在出了点问题。都要花很长的时间去调试。确实很不爽。
qiezi 2007-06-14
RyanPoy 写道
qiezi 写道
劳骚完了,好像也有点改观。


我之前的项目基本上逻辑部分依赖于单元测试,接口部分则依赖于语法检查,通常单元测试过了以后,编译没问题上线跑问题也不大,架构清晰就行。同事基本上不写单元测试,结果是写完代码之后据他说要认真地看上20-30遍,完全把自已当编译器使了。



想问问,你的单元测试是怎么个测法。又没有借助什么测试工具。还是自己写main方法进行测试。我发现我现在的做法,有点像你的同事了。一般是一个功能块完全写完了后再测试。现在出了点问题。都要花很长的时间去调试。确实很不爽。

可以用cppunit,自已写main也可以,简单用assert就可以,它会报告测试失败的行,不过有一个错误它就会退出,不像cppunit会把所有测试执行完,告诉你哪些成功哪些失败。

分层架构测试通常比较方便,不分层的写测试会非常困难,所以单元测试规划好了,也有助于把层次、接口弄得清晰。
Global site tag (gtag.js) - Google Analytics