覆盖标准函数

7

我想覆盖一个std函数的行为,比如说std :: time。是否可以调用std :: time并将其路由到我的自定义函数中?


澄清一下:我想劫持另一个预编译库中的 ::time 使用。 可移植性并不重要。假设编译器和平台非常具体且永远不会更改。 - Tim
3
在这种情况下,不行,C++无法完成。可能可以在C++之外实现技术上的修改。修改运行时库并挂钩进去。但是一旦库被编译,它调用的函数就是固定的了。它不会在运行时进行名称查找和重载分辨。它只是调用在编译时确定的函数。如果编译器确定应该调用标准的std:: time函数,那么它已经生成了调用它的代码。 - jalf
@jalf,你真的应该把你的评论写成一个答案。 - Dima
1
True,Tim的评论应该被编辑到问题中。 :) - jalf
5个回答

12

std 命名空间通常是受限制的,不允许添加新函数、重载、类或其他任何东西到 std 命名空间中,这属于 **未定义行为**。

唯一的例外是模板特化。 您可以提供在std命名空间中的函数特化。 一个经常进行此操作的函数是 std::swap


5
这听起来像是一个非常糟糕的想法。有点像重新定义truefalse。更好的方法是编写自己的包装函数,比如说tim_time(),它可以在内部调用std::time(),也可以不调用。

2

不要称之为std::time,而是通过不同的命名空间路由所有可能被覆盖的调用。

namespace mystd{
    using namespace std;
    void time() { ... }
}

// ...
mystd::time();  // not std::time
mystd::copy(...); // calls std::copy, unless you override it like time()

那么对 mystd::time 的调用将会调用该函数的修改版本。如果你调用未被覆盖的函数,例如 mystd::copy,它将正确地解析为原始的 std 函数。


1

不具有可移植性。在理解标准未定义发生什么的前提下,您通常可以在命名空间std中定义任何符号和函数,或链接到定义这些符号的库,或者其他操作。这只是未定义的行为。因此,您所能做的就是尝试并希望它不会在编译器的下一个版本中出现问题。

话虽如此,对于大多数编译器而言,它可能会基本正常工作,只要避免与“真正”的std::time发生一次定义规则冲突即可。这是因为大多数编译器实际上并没有对命名空间std进行任何特殊处理,它们用于实现它的头文件和库与您自己编写的头文件和库没有什么不同。

然而,Dima绝对是正确的,这样做几乎总是一个非常糟糕的想法。也许如果您被困在某个调试地狱中,基本上想要向std::time添加日志记录但无法实现,那么值得考虑。否则不要这样做。如果您想测试一些代码,以查看它是否在各种时间下正确工作,则将该代码传递给一个参数(或模板参数),指定应调用哪个时间函数。


1
在某些平台上,您可以执行此操作。在您的源代码中定义函数,例如:
extern "C" time_t time(time_t *value)
{
        ...
}

如果你很幸运,链接器会将你的版本的std::time与标准库中的版本绑定得更紧密。当然,这并不保证会起作用,或者以你想要的方式链接。而且,缺点是你再也无法访问原始的std::time了。

正如其他人发布的那样,这种行为并不可移植。我相信它在Linux上可以工作。我也相当确定它在Windows上不起作用(链接器会抱怨冲突)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接