Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 对具有私有可访问性的重载继承函数使用声明_C++_Inheritance_Overloading - Fatal编程技术网

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

C++ 对具有私有可访问性的重载继承函数使用声明,c++,inheritance,overloading,C++,Inheritance,Overloading,我有一个类似这样的类: class A { public: void foo(int arg) { foo(arg, false); } private: void foo(int arg, bool flag) {} }; 它是这样构建的,因为我只希望foo的标志参数在从A外部调用时为false。我想私下继承它,但允许调用foo: class B : private A { public: using A::foo; }; 但是,这失败了,因为using声明试图将f

我有一个类似这样的类:

class A
{
public:
    void foo(int arg) { foo(arg, false); }
private:
    void foo(int arg, bool flag) {}
};
它是这样构建的,因为我只希望
foo
的标志参数在从
A
外部调用时为false。我想私下继承它,但允许调用
foo

class B : private A
{
public:
    using A::foo;
};
但是,这失败了,因为using声明试图将
foo
的所有重载都纳入范围,包括编译器正确拒绝的私有重载

这并不难解决,我也可以:

  • A::foo(int,bool)
    的可访问性更改为protected或public
  • 公开继承
    A
    ;只有
    foo
    的公共重载将被继承
  • 更改
    A::foo(int,bool)
    的名称,以便using声明不会试图将其纳入范围
  • 这是一个小型的私有项目,而且,重载只在
    a
    内部调用。因此,解决问题在这里不是问题。(我只想重命名私有重载。)


    但我觉得这不是必须的。为什么using声明试图将不可访问的方法引入范围?这个特殊情况是否不在标准范围内?除了我列出的方法之外,还有什么方法可以解决这个问题吗?

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

    class B : private A
    {
    public:
        void foo(int arg) { A::foo(arg); }
    };
    
    在这种情况下,using声明对于工具来说太生硬了。它将函数名引入派生类范围。当这个名字指的是私人的东西时,它就窒息了。它无法区分重载。本标准要求using声明引入的名称可以访问:

    在未命名构造函数的using声明器中 引入的声明集应可访问。在一个 使用命名构造函数的声明器,不需要进行访问检查 表演。特别是,如果派生类使用using声明符 要访问基类的成员,成员名称应为 容易接近如果名称是重载成员函数的名称,则 所有命名的函数都应可访问。基类成员 使用声明人提及的内容应在at范围内可见 类的至少一个直接基类,其中 指定了使用声明器


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

    class B : private A
    {
    public:
        template<typename ...Args>
        void foo(Args ...args) { A::foo(args...); }
    };
    
    B类:私人A
    {
    公众:
    模板
    void foo(Args…Args){A::foo(Args…;}
    };
    

    它与using声明类似,只是访问说明符仅在模板实例化时检查,即在调用函数时检查。因此,模板将根据其范围而不正确地形成,并且在A/<代码>中是否可以访问该成员。

    < P>我发现了Scott Meyer有效C++中的下列与您的困境有关的摘录(重点添加):

    第33项:避免隐藏继承的名称。

    这意味着如果您从具有重载函数的基类继承 如果您只想重新定义或覆盖其中的一部分,则需要 为每个名称包含一个using声明,否则将隐藏该名称。 如果不这样做,您希望继承的某些名称将被隐藏。

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

    但是,在私有继承下,它可以 有道理。例如,假设派生私有继承自 而派生函数要继承的唯一版本是 一个不带参数的。在这里,使用声明不会起作用, 因为using声明使所有继承的函数都具有给定的 在派生类中可见的名称。
    不,这是另一种技术的情况,即简单的转发功能:


    我想我没有考虑过这一点,尽管我不希望在使用
    时编写这样的函数。@jpfx1342-这是有选择地引入函数的唯一方法。正如我所说,using声明用于名称。所以它总是被命名为
    foo
    ,或者什么都没有。@JeJo我宁愿使用
    使用
    声明,也不愿重新定义函数。我认为它更干净,更清楚的是它是相同的功能。重命名它只会让事情变得更糟。@acocagua-这正是using声明所做的。访问说明符不会影响可见性。事实上,很少有上下文可以在C++中隐藏名字。不管是好是坏,这就是我们的语言设计。@jpfx1342-我想到了另一个选择。请阅读答案中的新材料。在某种程度上,你可以吃蛋糕,也可以吃蛋糕。听起来像是一个编译器错误。。。您使用的是哪种编译器?调用私有重载被GCC(5.5和8.1)拒绝,这是它应该是的,私有重载仍然是私有的,即使使用声明。@Aconcagua-这不是一个bug。是的,我不希望using声明神奇地提供对私有重载的访问。我只是没想到它会尝试将私有重载引入范围。我已经用gcc、clang和msvc测试了这种行为。(在在线编译器Godbolt上)所有编译器都会抛出一个错误,所以我假设这是预期的行为。@StoryTeller啊,我想是的。我想我只是希望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 
       }; 
    }