打印

「毁灭战士3」源码就是“保持简洁”的证明

[复制链接]
1364|33
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主

假如你在网上搜最好的C++源代码。「毁灭战士3 | Doom 3」的源代码肯定会被提到好多次,这篇就来证明此事。

我花了一些时间通读了 DOOM3 的源代码。这可能是我见过的最干净最漂亮的代码了。

DOOM3是id Software公司开发 Activision发行的视频游戏。该游戏为id Software赢得了商业上的成功,已售出350万多份拷贝。


相关帖子

沙发
elecintop|  楼主 | 2015-3-24 20:05 | 只看该作者
在2011年11月23日,id Software维持开源传统,发布了他们上一个引擎的源代码。这份源代码已经被很多开发者审查,这里就有个fabien反馈的例子(链接):

DOOM3 BFG是用C++写的,一种庞大的语言,它既能写出优秀的代码,但也让人憎恶到眼睛流血。幸运的是,id Software退而求其次,使用C++子集,接近于“带类的C”,如以下几条约束:

没有异常
没有引用(使用指针)
少用模板
使用常量(Const everywhere)

多态
继承

使用特权

评论回复
板凳
elecintop|  楼主 | 2015-3-24 20:05 | 只看该作者
很多C++专家不建议使用“带类的C”这样的方法。然而,DOOM3从2000开发至2004,没有使用任何现代C++机制。

让我们使用 CppDepend 来看看源代码,探索它得特别之处。

使用特权

评论回复
地板
elecintop|  楼主 | 2015-3-24 20:06 | 只看该作者
DOOM3有少量的几个工程组成,这儿有它的工程列表和一些类型统计。

使用特权

评论回复
5
elecintop|  楼主 | 2015-3-24 20:06 | 只看该作者
这里还有他们之间的依赖关系图:

使用特权

评论回复
6
elecintop|  楼主 | 2015-3-24 20:07 | 只看该作者
DOOM3定义了很多全局函数。但是,大部分内容实现是在类中。

数据模型使用结构体定义。为了在源代码中对结构体的使用有个更具体的理解,在下图中将它们以蓝色分块显示出来。

在图表中,代码被表示为树形图,树形图表示法能使用嵌套的矩形来表示树状结构。而树结构用来表示代码分层结构。

使用特权

评论回复
7
elecintop|  楼主 | 2015-3-24 20:07 | 只看该作者
工程包含命名空间。
命名空间包含类型。
类型包含函数和域(field)。

使用特权

评论回复
8
elecintop|  楼主 | 2015-3-24 20:08 | 只看该作者

我们可以观察到它定义了许多的结构体,比如DoomDLL 40%的类型都是结构体。它们被有条理地用来定义数据模型。该实践已经被很多工程所接受,这种方法有个最大的缺点是多线程应用,结构体的public变量并非不可改变的。

使用特权

评论回复
9
elecintop|  楼主 | 2015-3-24 20:09 | 只看该作者
为何支持不可变对象,有个重要原因:能显著地简化并发编程。考虑下,写个合格的多线程程序是个艰巨的任务吗?因为很难同步线程访问资源(对象或者其他OS资源)。为什么同步这些操作很困难呢?因为很难保证在资源竞争状态下多线程对多个对象进行正确的读写操作。假如没有写操作呢?换句话说,线程只访问这些对象,而不做任何变动?这样就不再需要同步操作了!

使用特权

评论回复
10
elecintop|  楼主 | 2015-3-24 20:10 | 只看该作者
让我搜索下只有一个基类的类:

使用特权

评论回复
11
elecintop|  楼主 | 2015-3-24 20:10 | 只看该作者
几乎40%的结构体和类都只有一个基类。通常,OOP(面对对象编程)使用继承的好处之一是多态,下面蓝色标明了源代码中的虚函数:

使用特权

评论回复
12
elecintop|  楼主 | 2015-3-24 20:11 | 只看该作者
超过30%的函数是虚函数。少数是纯虚函数,下面是所有虚基类列表:

使用特权

评论回复
13
elecintop|  楼主 | 2015-3-24 20:11 | 只看该作者
只有52个类被定义为虚基类,其中35个类只是纯接口,也就是这些接口都是纯虚函数。

使用特权

评论回复
14
elecintop|  楼主 | 2015-3-24 20:12 | 只看该作者
我们来搜搜使用了RTTI的函数

使用特权

评论回复
15
elecintop|  楼主 | 2015-3-24 20:12 | 只看该作者

只有非常少的函数使用了RTTI。

为保证只使用OOP最基础的概念,不使用高级设计模式,不过度使用接口和虚基类,限制了RTTI的使用并且数据都定义为结构体。

使用特权

评论回复
16
elecintop|  楼主 | 2015-3-24 20:13 | 只看该作者
至此这份代码跟很多C++开发者所批评的“带类的C”没太大区别。

其开发者的一些有趣的选择,帮助我们理解它的奥秘:

使用特权

评论回复
17
elecintop|  楼主 | 2015-3-24 20:13 | 只看该作者
1-为有用的服务提供公用的基础类。

许多类是从idClass继承下来的:

使用特权

评论回复
18
elecintop|  楼主 | 2015-3-24 20:13 | 只看该作者
idClass提供如下服务:

创建实例化
类型管理
事件管理

使用特权

评论回复
19
elecintop|  楼主 | 2015-3-24 20:14 | 只看该作者

使用特权

评论回复
20
elecintop|  楼主 | 2015-3-24 20:14 | 只看该作者
2-方便的字符串操作

一般来说,字符串是一个项目里用的最多的对象,许多地方需要使用它,并且需要函数来对其进行操作。

DOOM3定义了idstr类,几乎包含了所有用的字符串操作函数,无需再自己定义函数来接受其它框架所提供的字符串类。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

176

主题

1329

帖子

3

粉丝