C++:隐藏一些函数

Posted

技术标签:

【中文标题】C++:隐藏一些函数【英文标题】:C++: hiding some functions 【发布时间】:2011-05-23 22:04:32 【问题描述】:

我重新定义了一些数学函数(以便它们更快 - 即:不太准确 - 或使用模板)。我将这些函数放在一个命名空间中,它们工作得很好。

不过,我经常忘记从我的命名空间调用函数(即:当我想调用 cos 时,我忘记写 mymath::cosusing mymath::cos;),而且很难找出在哪里调用我忘记了(直到现在我只是通过分析才发现它)。

考虑到

在我的数学标头中包含标准 math.hcmath 标头,并且 我需要包含标准数学标头(因为我的一些函数只是标准函数的包装器,我希望它们是内联的或者是模板化的),

如果使用全局命名空间(即:没有命名空间)数学函数,是否有一种可移植的方式隐藏标准数学函数,以便报告编译错误?

一个解决方案可能是在我的数学头文件的底部放置一个using namespace mymath;,但这个解决方案似乎并不那么好:它破坏了命名空间的整个目的;我宁愿明确说明是使用来自mymath 还是来自std 的函数,这样我就不得不在溃烂或更准确的函数之间做出选择,而不会忘记它。


编辑

许多答案说如果我使用全局命名空间中的cos(不使用stdmymath),并包含cmath(而不是math.h),编译应该会失败。

我不知道标准对此有何规定,但是:

#include <cmath>
int main( ) 
    cos( M_PI );
    return 0;

使用 GNU GCC (g++) 4.5.1(和旧版本)编译良好。

【问题讨论】:

关于编辑你是正确的:“未指定这些名称是否首先在全局命名空间范围内声明,然后通过显式使用声明注入命名空间 std”。 【参考方案1】:

把它放在一个头文件中,并#include 它无处不在:

namespace DontUseMe   
double cos (double) ;  
// ...etc.  
  
using namespace DontUseMe ;

【讨论】:

呃,这看起来不错!使用 Boost.StaticAssert 每当我使用全局命名空间数学函数时,它都会给我编译时错误... 当你这样做并且在某些编译单元中包含cmath 时,编译器会告诉你double cos(double) 是模棱两可的。因此命名空间 wrestling ;) @Fritschy:这就是重点!它强制使用显式命名空间限定符。这正是 OP 想要的。 好吧,TonyK,:) 没想过故意破坏程序 :)。【参考方案2】:

如果您只包含 cmath 而不是 math.h,则该标头中的所有函数都应位于 std:: 命名空间中。永远不要使用using namespace std;,你会没事的。 (cmath 只是 math.h 与命名空间中的所有东西)

【讨论】:

不,不是来自 GNU GCC 4.5.1 的 cmath。我的意思是,是的,它在 std 命名空间中提供数学函数,但它在全局命名空间中提供数学函数(即:::cos,没有任何命名空间),这是我想要避免的.【参考方案3】:

您是否需要在头文件中直接包含 math.h 和 cmath 头文件?如果确实需要,请尝试包含这样的标题:

namespace arbitrary_name

  #include <math.h>

这将包含一个新命名空间中的所有 math.h 定义,因此您不会在其他地方意外使用它们。

这不是理想的解决方案。也许有更好的方法可以使用匿名命名空间来做到这一点,但我并不清楚解决方案。

【讨论】:

这会起作用,但前提是math.h 仅包含 C 代码。我更喜欢包含cmath,以便它声明许多具有相同名称的标准函数的重载函数(即:double cos(double x);float cos(float x); ...)。 -- 无论如何,我认为这是我能做的最好的...... The River,这不起作用,因为该库导出的所有符号都不在您放入标头的命名空间中。【参考方案4】:

不幸的是,最可靠的解决方案是不使用与标准库相同的函数名。幸运的是,标准函数名称很简洁,并且被大量缩写,因此诸如 cosine()sine()exponent()arctan() 之类的名称将是独一无二的(并且可以说更好),而不必用笨拙的前缀来装饰名称。

或者,您可以保留相同的名称但将它们大写:Sin()Cos()Exp() 等。

【讨论】:

它当然可以,但是由于我忘记显式使用给定的命名空间,我相信我经常会忘记将自定义名称用于标准函数。但是,找到我使用标准函数名称的位置会更容易...... 我宁愿选择全名也不愿大写。 @Matthieu:我完全同意,这很可怕,但可能会吸引一些人。【参考方案5】:

这个思路怎么样:在包含之后,使用define如下:

#define sin blahblahblah    (just to generate an error)
#define cos blahblahblah    (just to generate an error)

发生的情况是,每一个罪都会被 blahblahblah 代替,这将导致错误。但是会发生的情况是 mymath::sin 将被 mymath::blahblahblah 替换(因为 #define 是字面意思),所以它也会产生错误。在这种情况下,如果您想让任务更轻松,您只需在 mymath 中临时定义函数 blahblahblah 以避免显示 mymath::sin 错误,然后编译并修复所有这些错误。

但是,我建议只制作“在文件中查找”并完成所有功能,我相信对于一个非常大型的项目来说,它不会超过一个小时。

希望对您有所帮助。

问候, 拉菲德

【讨论】:

这是一个可能的解决方案。标准库中的标准数学函数通常是宏。 嗯,希望能在编译时找到一种方法,无需两个编译步骤(一个检查函数有效性,另一个实际编译)......无论如何是的,这个会工作的。 这行不通,您必须将它们定义为函数样式的宏,并且您必须检查和 undef 它们,因为它们被允许在 @ 中成为宏(以及函数) 987654323@。如果您使用非函数样式的宏,那么任何使用 (std::sin)(x)(mymath::sin)(y) 的尝试仍会被这些宏破坏。 这是不允许的:“包含标准库头文件的翻译单元不得在任何标准库头文件中声明#define 或#undef 名称” @Charles,是的,它们是非函数宏样式,仅用于对函数名称进行重新映射。我已经在回答中解释了这一点,这就是为什么我建议他在 mymath 命名空间中定义函数 blahblahblah。【参考方案6】:

在单独的文件中编写一些包装函数。

#include <math.h>

namespace my_wrapper


float sin(float n)

    return std::sin(float n);


;

或者类似的东西。然后只在您的其他文件中使用它们,甚至不包含或在其他源文件中。是的,为它们都编写转发函数有点痛苦,但这只是一项临时工作,而且没有那么多......

使用现代编译器可以链接时间代码生成并且可以跨目标文件内联,这应该不会是低效的......

【讨论】:

模板怎么样? template&lt; typename T1, typename T2 &gt; PROMOTE(T1,T2) pow( T1 x, T2 y ) return std::pow( (PROMOTE(T1,T2)) x, (PROMOTE(T1,T2)) y ); ? (PROMOTE 是我定义的一个宏,它使用模板来提升类型 - 即:PROMOTE(int,double) 是 double)。【参考方案7】:

到目前为止,Clifford 是我最喜欢的答案,但您可能会想到另一种选择:修改此项目的标准标题(仅)。

您选择的编译器应该有一个选项来指示标准库所在的位置,因此您可以在项目中复制 STL,并修改文件,以便不再将有问题的名称注入全局命名空间。

这是 hackish,但这是我能想到的唯一方法,没有使用脚本检查代码中是否出现任何不合格的 cos / sin(即紧接在 :: 之前)。

【讨论】:

以上是关于C++:隐藏一些函数的主要内容,如果未能解决你的问题,请参考以下文章

C++ 隐藏继承层次结构中的成员函数,紧盯 CRTP

在 C++ 库中隐藏 C 头文件中的函数

C++中,一个类,究竟有多少隐藏的默认函数?

c++ 函数的隐藏和覆盖

C++ 虚函数被隐藏

如何在 C++ 中模拟覆盖父函数(不隐藏)?