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

时间:2018-09-04 04:43:19

标签: c++ inheritance overloading

我有一堂课,看起来像这样:

class A
{
public:
    void foo(int arg) { foo(arg, false); }
private:
    void foo(int arg, bool flag) {}
};

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

class B : private A
{
public:
    using A::foo;
};

但是,这失败了,因为使用声明试图将foo的重载引入{em> all ,包括编译器正确拒绝的私有变量。

这并不难解决,我可以:

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

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

但是,似乎没有必要。为什么using声明尝试将不可访问的方法纳入范围?标准是否不包括这种特殊情况?除了我列出的方法之外,还有其他方法可以解决此问题吗?

2 个答案:

答案 0 :(得分:4)

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

class B : private A
{
public:
    void foo(int arg) { A::foo(arg); }
};

在这种情况下,using声明实在是一个工具。它将功能 names 引入派生类范围。当名字指的是私人的东西时,它会令人窒息。它无法区分过载。该标准要求using声明引入的名称必须可访问:

  

[namespace.udecl]/17

     

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


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

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

类似于using声明,它是“包罗万象的”,只是仅在模板实例化时(即在调用函数时)检查访问说明符。因此,模板将根据模板的范围以及是否可以访问A中的成员而变形。

答案 1 :(得分:2)

我从Scott Meyer的Effective C ++中发现了以下摘录,该摘录与您的困境有关(重点强调):

  

项目33:避免隐藏继承的名称。
  ...
  这意味着如果您从具有重载函数的基类继承   而您只想重新定义或覆盖其中的一些,则需要   为您要隐藏的每个名称包含使用声明。   如果您不这样做,您想要继承的一些名称将被隐藏。
  ...

     

可以想象您有时不想继承所有功能   从您的基类。在公共继承下,这应该   永远不会这样,因为它再次违反了公共继承的is-a   基类和派生类之间的关系。 (这就是为什么使用   上面的声明在派生类的公共部分中:   在基类中公开的也应该在公开中公开   派生类。)

     

在私有继承下,它可以   合理。例如,假设Derived私下继承自   Base,并且Derived想要继承的函数的唯一版本是   一不带参数。 使用声明不能解决问题,   因为using声明使所有继承的函数具有给定的   名称在派生类中可见
  不,这是另一种技术的情况,即简单的转发功能:

class Base {
public:
   virtual void mf1() = 0;
   virtual void mf1(int);
... // as before
};
class Derived: private Base {
public:
   virtual void mf1() // forwarding function; implicitly
   { 
      Base::mf1(); } // inline 
   }; 
}