使用具有私有可访问性的重载继承函数的声明

jpf*_*342 3 c++ inheritance overloading

我有一个看起来像这样的课程:

class A
{
public:
    void foo(int arg) { foo(arg, false); }
private:
    void foo(int arg, bool flag) {}
};
Run Code Online (Sandbox Code Playgroud)

它是这样构建的,因为我希望foo'flag 参数仅在从外部调用时为 false A。我想私下继承它,但允许调用foo

class B : private A
{
public:
    using A::foo;
};
Run Code Online (Sandbox Code Playgroud)

但是,这失败了,因为 using 声明试图将 的所有重载foo带入范围,包括编译器正确拒绝的私有重载。

这不难解决,我也可以:

  1. 将可访问性更改A::foo(int, bool)为 protected 或 public
  2. A公开继承;只会foo继承的公共重载
  3. 更改名称,A::foo(int, bool)以便 using 声明不会尝试将其引入范围

这是一个小型的私有项目,此外,该重载仅在内部调用A。所以解决这个问题在这里不是问题。(我只是要重命名私有重载。)

但感觉应该没有必要。为什么 using 声明试图将不可访问的方法带入范围?这个特殊情况是不是标准没有涵盖?除了我列出的方法之外,还有其他方法可以解决这个问题吗?

Sto*_*ica 5

您还可以重新定义所需的重载,并将其参数转发给 中的函数A

class B : private A
{
public:
    void foo(int arg) { A::foo(arg); }
};
Run Code Online (Sandbox Code Playgroud)

在这种情况下, using 声明是一个过于生硬的工具。它将函数名称带入派生类作用域。当这个名字指的是私人的东西时,它会窒息。它无法区分重载。该标准要求 using 声明引入的名称是可访问的:

[命名空间.udecl]/17

在未命名构造函数的 using 声明符中,引入声​​明集的所有成员都应可访问。在命名构造函数的 using 声明符中,不执行访问检查。特别是,如果派生类使用 using-declarator 访问基类的成员,则成员名称应该是可访问的。如果名称是重载成员函数的名称,则所有命名的函数都应该是可访问的。using-declarator 提到的基类成员应在指定 using-declarator 的类的至少一个直接基类的范围内可见。


转发功能也可以模板化。因此,无需重新定义他们想要单独公开的每个函数。

class B : private A
{
public:
    template<typename ...Args>
    void foo(Args ...args) { A::foo(args...); }
};
Run Code Online (Sandbox Code Playgroud)

它像 using 声明一样“包罗万象”,除了仅在模板实例化时检查访问说明符,即在调用函数时。因此,模板将根据其范围以及成员在A那里是否可访问而格式错误。