2009-10-18 36 views

回答

2

至于monkey patching指的是动态变化的代码,我无法想象这到底是怎么用C++实现...

+0

是否有一个特定的词为猴子补丁的动力不足一半?东西像const_cast,访问控制重定义和RTTI滥用? – 2009-10-18 13:55:43

3

我想这取决于你想要做什么。如果你已经链接了你的程序,你将很难替换任何东西(实际上并没有改变内存中的指令,这可能也是一个延伸)。但是,在此之前,有选择。如果你有一个动态链接的程序,你可以改变链接器的运行方式(例如LD_LIBRARY_PATH环境变量),并让它链接别的东西而不是目标库。

看看valgrind的例子,它取代了许多其他正在处理的魔法东西之间的标准内存分配机制。

3

考虑猴子补丁的“游击第三方库使用”方面,C++提供了大量的设施:

  • const_cast让你解决热心const声明。
  • #define private public在标题包含之前,您可以访问私有成员。
  • 子类和use Parent::protected_field允许您访问受保护的成员。
  • 你可以在链接时重新定义一些东西。

如果您正在编译的第三方内容已经编译完成,但是动态语言中可行的大部分内容并不容易,而且通常根本无法实现。

4

要添加到其他答案,请考虑通过共享对象或DLL(取决于平台)暴露的任何函数可以在运行时被覆盖。 Linux提供了LD_PRELOAD环境变量,它可以指定一个共享对象加载到所有其他对象之后,这可以用来覆盖任意函数定义。它实际上是为单元测试提供“模拟对象”的最佳方式,因为它不是真正的入侵。但是,与其他形式的猴子修补不同,请注意,像这样的变化是全球性的。您不能指定一个特定的呼叫不同,而不会影响其他呼叫。

5

不容易这样,并且由于大型项目的危险性,您最好有充足的理由。

预处理器可能是最好的候选者,因为它对语言本身并不了解。它可以用来重命名属性,方法和其他符号名称 - 但替换是全局的,至少对于单个#include或代码序列。

我之前曾经用它来击败“图书馆钻石”进入提交 - 图书馆A和B都导入了一个操作系统库S,但以不同的方式使得一些S的符号将被命名为相同但不同。 (命名空间是不可能的,因为它们会产生更深远的影响)。

同样,你可以用兼容但优越的类来替换符号名称。 例如在VC中,#import生成一个使用_bstr_t作为类型适配器的导入库。在一个项目中,我已经成功地将这些_bstr_t使用替换为与其他代码更好互操作的兼容类,只是将#define'ing _bstr_t作为我的替换类#import

修补虚拟方法表 - 无论是替换整个VMT或个别方法 - 是我遇到的别的东西。它需要很好地理解你的编译器如何实现VMT。我不会在真实生活的项目中这样做,因为它依赖于编译器内部,并且在Thign改变时不会收到任何警告。不过,了解C++的实现细节是一个有趣的练习。一个应用程序将在运行时从初始化程序/加载程序存根切换到完全或甚至与数据相关的实现。

动态生成代码在某些场景中很常见,例如转发/过滤COM接口调用或将OS窗口句柄映射到库对象。我不确定这是否仍然是“猴子补丁”,因为它不是真的玩弄语言本身。

+0

至于依赖于编译器内部,当事情发生变化时,你可以得到一个警告 - 只需要在单元测试中建立你需要的断言。在实践中,这对我非常有效(不是用vtable修补,而是在其他情况下,我试图编写依赖于特定STL实现方面的代码)。 – 2009-10-18 23:18:15