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

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

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

我花了一些时间通读了 DOOM3 的源代码。这可能是我见过的最干净最漂亮的代码了。DOOM3是由id Software公司开发、Activision发行的视频游戏。该游戏为id Software赢得了商业上的成功,已售出350万多份拷贝。

在2011年11月23日,id Software维持开源传统,发布了他们上一个引擎的源代码。这份源代码已经被很多开发者审查,这里就有个fabien反馈的例子(链接):

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

  • 没有异常
  • 没有引用(使用指针)
  • 少用模板
  • 使用常量(Const everywhere)
  • 多态
  • 继承

很多C++专家不建议使用“带类的C”这样的方法。然而,DOOM3从2000开发至2004,没有使用任何现代C++机制。

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

DOOM3由少量的几个工程组成,这儿有它的工程列表和一些类型统计。

以及它们之间的依赖关系图:

 

DOOM3定义了很多全局函数。但是,大部分内容实现是在类中。

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

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

  • 工程包含命名空间。
  • 命名空间包含类型。
  • 类型包含函数和域(field)。

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

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

让我搜索下只有一个基类的类:

几乎40%的结构体和类都只有一个基类。通常,OOP(面对对象编程)使用继承的好处之一是多态,下面蓝色标明了源代码中的虚函数:

超过30%的函数是虚函数,少数是纯虚函数,下面是所有虚基类列表:

只有52个类被定义为虚基类,其中35个类只是纯接口,也就是这些接口都是纯虚函数。

我们来搜搜使用了RTTI的函数

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

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

至此这份代码跟很多C++开发者所批评的“带类的C”没太大区别。

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

1-为有用的服务提供公用的基础类。

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

idClass提供如下服务:

  1. 创建实例化
  2. 类型管理
  3. 事件管理

2-方便的字符串操作

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

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

3-源代码与GUI框架(MFC)高度解耦

很多工程用了MFC后,它的代码就会与MFC类型高度耦合,并且在代码的任何一处都能发现MFC类型。

在DOOM3里,代码和MFC是高度解耦的,只有GUI类才会直接依赖它。下面的CQLinq查询可以展示这点:

这样的选择对生产力有很大的影响。事实上,只有GUI开发者才会关心MFC框架,其它开发者不应该被强制在MFC上浪费时间。

4-提供了非常好的公共函数库(idlib)

几乎在所有项目中都会用到公共工具类,就如以下查询的结果:

正如我们所看到经常使用的就是公共工具类。假如C++开发者不使用一个良好的公共工具框架,那就会为解决技术层面问题花费大部分的开发时间。

idlib提供了很多有用的类用于字符串处理,容器和内存。有效促进了开发者的工作,并且能让他们更多的关注在游戏逻辑上。

5-实现非常易于理解

DOOM3实现了非常难的编译器,对于C++开发者而言,开发语法解析器和编译器不是件轻松的事。尽管如此,DOOM3的实现非常容易被理解并且编写得十分干净。

这儿有这些编译器的类的依赖图:

这儿还有编译器源代码的代码片段:

我们也看过许多语法解析器和编译器的代码,但这是第一次我们发现编译器是如此得容易理解,和整个DOOM3源代码一样。这太神奇了。当我们探究DOOM3源代码时,我们忍不住会喊:喔,这太漂亮了!

总结

即使DOOM3选择了很基础的设计,但它的设计者所做的决定都是为了开发者能更多的关注游戏逻辑本身,并且为所有技术层面的东西提供便利。这提高了多大的生产力啊。

无论何时使用“带类的C”,你应该明白你自己在干什么。你必须像DOOM3的开发专家一样。但不推荐初学者忽视现代C++建议而冒险。

原文发布时间:2015-01-24

本文来自云栖合作伙伴“linux中国”

时间: 2024-11-01 04:49:43

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

我对java String的理解 及 源码浅析

一.char说起到String 这也是自己第二次回过头来啃java基础书,小生自认为愚昧无知.如果大神有好的教育,可以评论私信.以下都是我的看法: 为什么说char 呢,我这里先卖个关子.在java中,char是用unicode编码的,占16位(2字节).从ansi编码(1字节)到unicode编码(2字 节).Java中使用Unicode的原因是,Java的Applet(网页)运行,Unicode里面包含最多最广比如:中 文,English,Spanish,German, French等.因此

这是一款仅针对「中国网民」的勒索软件(含源码下载)

在黑客的众多牟利手段当中,勒索软件可能是最普遍的一种.这种恶意软件通常会通过受感染的邮件附件.被篡改的网站或网页广告散布.勒索软件会对用户电脑上的文件进行加密,除非受害者交付特定数额的赎金,否则受影响的文件将会一直处于不可用的状态. 最近安全研究人员发现了一种新型恶意勒索软件cuteRansomware,而该恶意勒索软件正在使用谷歌文档工具Google Doc存储受害者的信息,更有趣的事情是,该恶意勒索软件源码在几个月前出现在了GitHub上,该项目名为my-Little-Ransomware,

读源码时,我们到底在读什么?

村上春村有本关于跑步的书:当我谈跑步时我谈些什么 而我们软件工程师,经常会提到读源代码,读优秀开源作品的源代码.我们谈起读源码时,到底是读什么呢? 读者可能会说,你这不是装X,明知故问嘛,读源码,当然就是读源码了. 当然,源码是我们阅读的对象,我前面的文章也提到了一些源代码阅读相关的内容.我今天想谈的是,我认为源码阅读除了提高设计能力外,也是学习相应实现语方语法与最佳实践的好例子,以及简洁代码.类/方法/变量等命名.注释编写等方面的榜样. 代码是写给人看的.这句话在许多编程的书里面都提到过.我们

iOS 热更新解读(二)—— JSPatch 源码解析

关于 JSPatch 的实现原理,JSPatch 作者本人 bang 已经有一系列文章阐述: JSPatch 实现原理详解 <一> 核心 JSPatch 实现原理详解 <二> 细节 JSPatch 实现原理详解 <三> 扩展 JSPatch 实现原理详解 <四> 新特性 JSPatch 实现原理详解 <五> 优化 这些文章是对 JSPatch 内部实现原理和细节诸如"require实现"."property实现&qu

为什么我们要阅读源码?

程序员每天都和代码打交道.经过数年的基础教育和职业培训,大部分程序员都会「写」代码,或者至少会抄代码和改代码.但是,会读代码的并不在多数,会读代码又真正读懂一些大项目的源码的,少之又少.这种怪状,真要追究起来,怪不得程序员这个群体本身 -- 它是两个原因造成的: 我们所有的教育和培训都在强调怎么写代码,并没有教大家如何读代码 大多数工作场景都是一个萝卜一个坑,我们只需要了解一个系统的局部便能开展工作,读不相干的代码,似乎没用 我常常把写代码和写作进行类比 -- 二者有很多相通之处;但从培养写代码

让你的「微信小程序」运行在Chrome浏览器上,让我们使用WebStorm

「微信小程序」的开发框架体验起来,还不错--自带了UI框架.但是问题是他的IDE,表现起来相当的糟糕--其实主要是因为,我当时买WebStorm License买了好多年.所以,我觉得他的IDE真不如我这个付费好用. 而且,作为一个拥护自由和开源的 「GitHub 中国区首席Markdown程序员」.微信在「微信小程序」引导着Web开向封闭,我们再也不能愉快地分享我们的代码了. 如果我们放任下去,未来的Web世界令人堪忧. 好了,废话说完了: 文章太长不想看,可以直接看Demo哈哈: 源码: h

胜思网络获《石器2》源码开发与更新授权

近日,胜思网络正式取得<石器时代2>源代码后续开发与更新授权,这意味着更多不同类型的.喜爱Q版回合网游玩家的更高需求将得到满足.据官方透露,关于<石器时代2>激活码官方将通过国内各知名游戏媒体门户,公会与投票活动方式限量发放.玩家届时可通过上述方式获取.目前胜思网络正在积极筹备研发团队,希望届时能够给石器时代的新老玩家带来惊喜. 早前,公司取得该款产品代理时就已考虑到 中国市场的情况,表示在中国大陆继续运营的这款Q版鼻祖的2D回合制经典产品,必须有"中国风"味,

源码资本曹毅:重点投互联网金融,看重产品型创业者

[核心提示] VC届和创业圈一样正在发生着变化,走向「小而美」.在新生代 VC 眼中,什么样的才是好产品呢? 2013 年以来,中国互联网迎来了赴美上市的一个巨大窗口期.大批公司成功上市的背后是 VC 的漂亮退出,这也让更多资金得以回笼,从而让新兴公司和产品拥有更加丰富的资金支持.另一方面,互联网使得一大批创业者实现了个人财务自由,这部分人愿意把他们的资金拿出来反哺前仆后继的新创群体. 在大笔资金涌入互联网行业的同时,投资界也在随之发生改变.为了能够更好地发挥自己的投资能力,以及获得更高的投资回

Ubuntu14.04环境编译vlc源码for安卓Android系统

一.准备虚拟机 1.所需软件 deamon:DTLite4491-0356.1394761051.exe VMware-workstation-full-12.1.0-3272444_for_x64.exe 序列号5A02H-AU243-TZJ49-GTC7K-3C61N ubuntu-14.04.1-desktop-amd64.iso 2.逐个安装,遇到报虚拟机无法跑长类型的ubuntu,按照错误提示,修改主板cmos参数:Intel VT-x BIOS/固件设置 中 开启 二.参考文档 参考