【问题标题】:How to limit a function scope in the same file as it is defined in c++?如何将函数范围限制在与 C++ 中定义的文件相同的文件中?
【发布时间】:2016-05-13 15:53:48
【问题描述】:

我有调用私有成员函数的公共成员函数。我想限制私有成员函数定义可用的文件中私有成员函数的范围。在C中,我在函数名前使用了static来限制其在文件中的作用域,在C++中如何实现。

class Base
{
  public:
  void XYZ1(void);
  void XYZ2(void);
  private:
  void fun(void);
};

void Base::XYZ1(void)
{
  fun();
}

void Base::fun(void)
{
  // do something;
}

现在,如果成员函数 XYZ2 是在其他 .cpp 文件中定义的,则不应允许从中调用 fun()。基本上将 fun() 函数限制在文件范围内。 在a1.cpp中

void Base::XYZ2(void)
{
  fun();// this should result in some error saying fun() is not defined in its scope.
}

【问题讨论】:

  • 我认为这样的事情是不可能的,至少不能以便携的方式。
  • C++ 也允许您使用static 进行内部链接,但它对成员函数有不同的含义。这不是 C 与 C++ 的问题。
  • fun() 必须是成员函数,还是非成员函数?
  • 唯一的解决方案是不让它们成为成员函数,而是“正常”的非成员函数。然后,您可以将它们设为 static,就像在 C 中一样,或者将它们放在匿名命名空间中。如果函数需要访问其他私有成员(函数或变量),这当然会导致问题,在这种情况下,您应该阅读the pimpl idiom
  • 学究式地说,staticlimits linkage, not scope.

标签: c++ namespaces


【解决方案1】:

我想在可以定义私有成员函数的文件中限制私有成员函数的范围。

private 成员函数不能被另一个类或函数使用,除非它们被该类授予 friend-ship。从这个意义上说,函数可以调用的范围已经是有限的。

话虽如此,类的任何成员函数或已被该类授予friend-ship 的任何类或函数都将能够调用private 成员函数。

防止该函数在定义它的文件之外被调用的唯一方法是使其成为 .cpp 文件中的非成员 static 函数。或将其放在 .cpp 文件中的匿名命名空间中。

【讨论】:

  • 或者放在.cpp文件中的匿名命名空间中。
【解决方案2】:

现在,如果成员函数 XYZ2 定义在其他 .cpp 文件中, 它不应该被允许从中调用 fun() 。基本上限制了 fun() 函数到文件范围。在a1.cpp中

您可以将函数放在匿名命名空间中(在使用的 cpp 文件中)。链接将变为内部链接,并且无法从任何其他文件访问该名称。将函数设为静态(在 cpp 文件中)时,也可以获得相同的效果。

如果您需要访问内部/私有成员,您可以使用嵌套类,其实现在相关 cpp 文件中定义:

//h
class Nesting
{
    //...
  private:
    struct MyPrivateFunctions;
};

//cpp

struct Nesting::MyPrivateFunctions
{
  static void f1(Nesting& this);
  static void f2(Nesting& this);
  //etc...
};

我已将 Nesting 作为参数传递给 MyPrivateFunctions 可以访问其私有成员(因为它是嵌套的,所以这是允许的)。

请注意,这与其他地方提到的 Impl 技巧非常相似,但它也允许在其他单元中独立定义成员函数,并且不需要实例化。

【讨论】:

    【解决方案3】:

    大多数人建议您在 C++ 中使用匿名命名空间。但是,这只有在您想做类似声明一个全局变量/函数时才可行,该全局变量/函数应该在定义它的文件中严格使用。

    我们不能按照 C++ 标准在类中使用命名空间,您可能想看看这个讨论:Why can't we declare a namespace within a class?

    我在函数名之前使用了 static 来限制它在文件中的范围。

    这对你有用,但这里的理解是错误的,因为静态从来没有打算用作范围说明符,它是一个存储说明符,它的生命周期是整个程序生命周期。您仍然可以通过多种方式从其他文件访问静态变量,但是这里的编译器不提供外部可见的链接器符号,因此其他翻译单元/文件无法访问。

    就公共成员函数而言,他们应该被允许从定义它的任何文件中使用这个私有函数。这样类成员函数之间的关系就不会被破坏。我想您现在将停止将静态视为范围说明符:)

    【讨论】:

      【解决方案4】:

      如果您不想向外部显示类的“隐藏”功能,也可以使用良好的旧隐式技巧。毕竟,私有函数仍然列在头文件中。

      // Foo.h
      class FooImpl; // forward declearation
      class Foo
      {
          FooImpl *m_pImpl;
          public:
          Foo(); // Default constructor (and any other) create instance of FooImpl.
          ~Foo();
      };
      
      // Foo.cpp
      class FooImpl
      {
         // members of hidden types, secrets, methods, ... anything you do not want to show to users of class Foo.
      };
      Foo::Foo() : m_pImpl(new FooImpl()) {}
      Foo::~Foo() 
      {
           delete m_pImpl; m_pImpl = nullptr;
      }
      

      可以看出,使用 impl 技巧,您不仅可以隐藏函数,还可以隐藏类的数据成员以及如果成员是 Foo 类的一部分将产生的类型依赖关系。

      【讨论】:

        【解决方案5】:

        解决此问题的一种方法是使用所谓的“外观”。基本上,你有两个类:第一个类有你想要隐藏的私有方法,而第二个类实现了一个包装器,它只提供你想要访问的方法。第二个类包装了第一个类的一个实例。这就是整个技巧的工作原理。

        https://en.wikipedia.org/wiki/Facade_pattern

        【讨论】:

          猜你喜欢
          • 2020-04-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-06
          • 1970-01-01
          • 2016-09-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多