如何在C ++中实现猴子补丁?

时间:2009-10-18 13:37:52

标签: c++

是否可以在C ++中实现猴子补丁? 或者任何其他类似的方法?

感谢。

5 个答案:

答案 0 :(得分:6)

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

答案 1 :(得分:6)

不可移植,并且由于大项目的危险,你最好有充分的理由。

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

之前我曾使用它来击败“库钻石” - 图书馆A和B都导入了OS库S,但是以不同的方式使得S的某些符号具有相同的名称但不同。 (命名空间是不可能的,因为它们会产生更深远的影响)。

类似地,您可以使用兼容但更高级的类替换符号名称。 例如在VC中,#import生成一个使用_bstr_t作为类型适配器的导入库。在一个项目中,我成功地将这些_bstr_t用法替换为兼容性足够的类,可以更好地与其他代码进行互操作,只需将#define'_bstr_t作为#import的替换类。

修补虚拟方法表 - 替换整个VMT或单个方法 - 是我遇到过的其他一些问题。它需要很好地理解编译器如何实现VMT。我不会在现实生活项目中这样做,因为它取决于编译器内部,并且当符号发生变化时你不会得到任何警告。但是,了解C ++的实现细节是一个有趣的练习。一个应用程序将在运行时从初始化程序/加载程序存根切换到完全或甚至数据相关的实现。

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

答案 2 :(得分:3)

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

以valgrind为例,它取代了标准内存分配机制(在其他很多其他神奇的东西中)。

答案 3 :(得分:3)

考虑到猴子修补的“游击队第三方库使用”方面,C ++提供了许多功能:

  • const_cast可让您解决热心的const声明。
  • 在包含标头之前,
  • #define private public可让您访问私人会员。
  • 子类化和use Parent::protected_field允许您访问受保护的成员。
  • 您可以在链接时重新定义许多内容。

如果提供的第三方内容已经编译好了,那么动态语言中的大部分内容并不容易,而且通常根本不可能。

答案 4 :(得分:2)

由于monkey patching是指动态更改代码,我无法想象如何在C ++中实现这一点......