【问题标题】:Can non-class functions be made private?非类函数可以私有化吗?
【发布时间】:2016-01-02 09:05:49
【问题描述】:

我创建的命名空间中有一些函数在整个程序中使用。

在头文件中:

namespace NQueens
{
    static int heur = 0;
    int CalcHeuristic(char** state, int size);
    void CalcHorzH(char ** state, int &heuristic, int size);
    void CalcColH(char ** state, int &heuristic, int size);
    void CalcDiagH(char ** state, int &heuristic, int size);
    int calcCollisions(int queensPerRow, int size);
}

一切正常。但是,实际上从我的外部程序代码中调用的唯一函数是 CalcHeuristic(char** state, int size) 函数。 该函数然后调用其他函数本身。

由于这些不属于一个类,我的编译器不会让我将其他函数声明为private。有没有办法做到这一点?我应该担心吗?

【问题讨论】:

  • 你想要一些神秘的东西。使用类 + 静态方法。
  • 我确实在我的代码中使用类和静态方法,我喜欢在某些情况下这样做,但这不是其中一种情况。
  • 请通过投票/接受答案来表达您的感激之情,而不是通过编辑“谢谢!”消息。
  • “我应该担心吗?” - 这是这个问题中最重要的部分。但我们无法回答。由您决定哪些事物属于软件组件的接口,哪些事物属于其实现
  • 作为任何面向对象设计的一般经验法则,除了预期的功能外,您不应将功能暴露给外界。

标签: c++


【解决方案1】:

您不能将独立函数设为私有。但是你可以在你的 cpp 文件中将它们定义为静态的,并且不在 .h 文件中提供它们的原型,这样外部调用者就无法调用它们。

编辑。对于这里所有的静态仇恨者,这里有一些需要考虑的事情。如果您想在定义函数之前声明它们(这可能是因为这是一种很好的做法,或者因为一个调用另一个函数是必需的),您将必须打开匿名命名空间,声明“隐藏”函数,关闭命名空间,定义你的可见函数,再次打开匿名空间,定义隐藏函数。

现在,虽然使用我寻找的编译器,但两个匿名命名空间具有相同的名称,并且可以正常工作,但这不是保证。

匿名命名空间的另一件事 - 尝试在他们的函数中放置一个断点。

【讨论】:

  • static 已被弃用。您应该改用匿名命名空间。无论如何,private 是面向对象的东西。而static - 不是逻辑可见性,而是链接时可见性。 (P.S. 我没有投反对票)
  • static 已被弃用,以防您没有注意到。
  • 是的,我试过了,但它不起作用。我的编译器抱怨未在此范围内声明的函数。
  • 你在这里做错了。静态确实有效。
  • 两个匿名命名空间保证在同一个翻译单元中具有相同的名称。请参阅 C++ 标准 §7.3.1.1:“在翻译单元中出现的所有 unique 都被相同的标识符替换,并且此标识符不同于翻译单元中的所有其他标识符。”
【解决方案2】:

如果函数必须是模板或内联函数,典型的解决方案是将它们放在名为 detail 的命名空间中,并假设人们不会访问它们。

否则,就不要在头文件中声明它们。

【讨论】:

    【解决方案3】:

    不要在标头中声明它们,将它们放在实现文件中的匿名命名空间中。

    示例标题:

    namespace NQueens
    {
        int CalcHeuristic(char** state, int size);
    }
    

    示例实现:

    namespace
    {
        static int heur = 0;
        void CalcHorzH(char ** state, int &heuristic, int size);
        void CalcColH(char ** state, int &heuristic, int size);
        void CalcDiagH(char ** state, int &heuristic, int size);
        int calcCollisions(int queensPerRow, int size);
    }
    
    namespace NQueens
    {
        int CalcHeuristic(char** state, int size)
        {
            // ...
        }
    }
    
    namespace
    {
        void CalcHorzH(char ** state, int &heuristic, int size) {}
        void CalcColH(char ** state, int &heuristic, int size) {}
        void CalcDiagH(char ** state, int &heuristic, int size) {}
        int calcCollisions(int queensPerRow, int size) { return 0; }
    }
    

    【讨论】:

    • @BradStell 听起来可能很花哨,但它是一个没有名称的命名空间(因此不能“从外部”引用)。见编辑。
    • 为什么在实现文件中分离成声明和定义?
    • @SergeyA: §7.3.1.1: “在翻译单元中出现的所有unique 都被相同的标识符替换,并且该标识符不同于翻译单元中的所有其他标识符。 "
    • @SergeyA 作为单个编译单元的一部分,定义多个匿名命名空间应该不是问题。
    • @SergeyA 在同一个翻译单元中,它是同一个命名空间(即,它的行为与命名时完全相同)。在翻译单元之间,它们的行为就好像它们的名字是唯一的一样。
    【解决方案4】:

    不,您不能制作独立功能private
    您可以做的不是在命名空间中声明它们,而是在翻译单元中使用匿名命名空间:

    在标题中:

    namespace NQueens {
        static int heur = 0;
        int CalcHeuristic(char** state, int size);
    }
    

    .cpp:

    namespace {
        void CalcHorzH(char ** state, int &heuristic, int size) {
           // Implementation
        }
        void CalcColH(char ** state, int &heuristic, int size) {
            // Implementation
        }
        void CalcDiagH(char ** state, int &heuristic, int size) {
            // Implementation
        }
        int calcCollisions(int queensPerRow, int size) {
            // Implementation
        }
    }
    

    另一种选择是使用类而不是命名空间,将所有这些函数包含为static 函数成员。然后,您可以使用所有常见的范围语义,如 privateprotectedpublic

    但 IIRC 此类类(仅包含 static 函数成员)不被认为是优先将函数独立放置到命名空间中的良好做法。

    虽然如果你想实现一种protected 继承,那么该方法可能会被认为是有用的。

    【讨论】:

    • @SergeyA 如果使用正确,可以保证工作。
    • 我试过这个,编译器不太喜欢它。说“函数的多个实例与参数列表匹配”
    • @BradStell 抱歉,我对示例的第一次编辑是错误的。实现也需要出现在匿名命名空间中,请参阅我最近的编辑。
    • 编辑。我错误地尝试了这个。 @molbdnilo 提供了一个更详尽的示例,说明您的建议确实有效。
    【解决方案5】:

    使用私有静态方法(伪代码):

    class NQueens
    {
    public:
      static void CalcHeuristic()
      {
        CalcColH();  // Legal here
      }
    
    private:
      static void CalcColH(){}
    }
    
    //...
    NQueens::CalcHeuristic(); // Legal
    NQueens::CalcColH(); // error
    

    Private - 是 OOP,它是逻辑可见性。 static 或匿名命名空间 - 是链接时可见性。

    【讨论】:

    • 我喜欢这种方法,并且在我的代码中经常使用这种方法。然而,在这个项目中,当我遇到我发布的问题时,我想尝试独立功能。
    猜你喜欢
    • 2015-02-13
    • 2012-06-16
    • 1970-01-01
    • 2021-07-20
    • 2017-05-23
    • 2015-10-06
    • 2011-08-04
    • 2011-08-24
    • 1970-01-01
    相关资源
    最近更新 更多