C/C++的缺陷之模块和实体引用,兼论C++的namespace

先从基础概念说起。

模块就是一组相关的实体的集合。该定义如此的简练以至于含糊不清,不过该概念非常强大,整个软件开发行业都是因为引入了该概念而充分发育起来的。比如我们常说的模块化什么的。

进一步的说,模块一般从概念上区分为接口和实现两个部分。主意,我说的是概念上。这就会导致我们可以相对抽象的看问题,可以解决比较复杂的大问题。

更进一步,模块对于不同的客户(显然也是别的模块),可以呈现出不同的接口。模块的客户显然不应该关注模块的实现。模块这个概念的引入就是为了这个目的,如果模块的用户需要知道模块的实现,那么,引入模块的好处就丧失殆尽,只有坏处了。

按照上面罗嗦的一大通,我们看看C/C++中的模块什么?套用概念,我们似乎发现:函数、类、名字空间等都可以是模块,但是不是。C/C++直接提供支持的模块单元是源文件。C/C++把源文件区分为两种,一种叫做头文件,提供模块的接口,一种叫做源文件,提供模块的实现。看起来非常优雅,不是么?

其实C、C++的模块机制非常粗鲁,非常差劲。

我逐一描述它们的缺陷。

一、接口和实现的物理分离。
这是一个非常差劲的选择,可是这个因为C/C++中的模块引用机制的问题不得不如此。不记得有多少次了,我没有能够保证接口和实现的同步导致各种极端难堪的问题出现。相信你一定经历过这种不同步的困扰。逻辑上的分离不需要物理上也分离的。绝对不需要。接口和实现本来就是一体两面的问题,分开来维护非常不自然,非常容易失去同步。

二、C/C++的模块引用机制。
这是一个被别人批烂了的东西,我还是要痛打落水狗的:)。简单的说,C/C++的模块引用机制是传递的。这就是说,如果模块A引用了模块B,而模块B引用了模块C的话,那么模块A也依赖于模块C了。有人会觉得这不算什么问题呀,我还正好希望这样的引用呢。可是,这会导致一个著名的问题叫做循环依赖(C/C++的引用机制决定了这叫做循环包含)。解决循环依赖的办法也不是没有,可是都不理想。方法一:维护一个依赖链表,每一个被依赖的模块都树一个旗标,表明到此一游过了,那么,下一次在到此的时候就过门而不入。这个方法的问题是,旗标一旦冲突,本来应该依赖的模块也被“过门而不入”了。方法二:编译器保证。这个方法是很好,唯一的问题是需要扩充编译器,造成不兼容的语言。当然,依赖的传递还会导致除了循环依赖以外的一大堆别的问题,模块间的依赖允许传递的话,会导致复杂的依赖图。而复杂的依赖图会导致修改传递,也就是说,一个修改影响一大片。这是很多人不愿意看到的。
是什么导致C/C++的模块引用机制如此龌龊?一切都是因为C/C++的模块引用机制是简单的文本copy机制。这个机制自然就会导致引用的传递,因而一起一大堆问题。C/C++为了避免这个问题,不得已才把模块分成两个部分以避免大多数问题,可是这个分割也有很多问题。

三、由于C++对象模型的限制,头文件中描述的接口其实不是纯接口。
这会导致对模块实现的修改也会影响一大片模块,当然,这个问题也是有办法解决的,不过不够自然。这样:

class C
{
public:
interface element;
....
privte:
impl element;
....
};

改成:

class C
{
public:
interface element;
....
privte:
implWarp× implWarpElement;
};

struct implWarp
{
impl element;
....
};

同时,上面两个实体要分别放入两个模块,只有真正需要了解C的实现的那些模块才引用implWarp所在地模块。这样就基本上实现了接口和实现的分离,不过需要多写一些东西,而且显得非常不自然。

四、C/C++的模块及引用机制不能对不同的模块展现不同的接口。
。。。。。

我靠,越写越多,还是先歇歇吧。以后再写。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值