【问题标题】:Overload pure virtual function with non pure virtual version [duplicate]用非纯虚拟版本重载纯虚拟功能[重复]
【发布时间】:2019-02-21 04:50:07
【问题描述】:

Base 和 Derived 定义如下:

class Base {

    public:
        virtual int f1(int a) const = 0;
        virtual int f2(int a, int b) const { return a+b;}
};

class Derived : public Base {

    public:
        int f1(int a) const { return a; }
}; 

int main() {
    Derived obj;
    cout << obj.f1(1) << endl;
    cout << obj.f2(1, 2) << endl;
}

结果是

1
3

obj.f1(1) 使用 Derivedobj.f2(1, 2) 中的 f1 实现em> 使用继承自 Base 的实现,这正是我想要的。

现在,我希望这两个函数具有相同的名称,f,因此当有两个参数时,基类提供了一个实现,而派生类必须实现单参数版本(即为什么它是纯虚拟的)。

但是,如果我这样做(只需将 f1f2 重命名为 f):

class Base {

    public:
        virtual int f(int a) const = 0;
        virtual int f(int a, int b) const { return a + b;}
};

class Derived : public Base {

    public:
        int f(int a) const { return a; }
};

int main() {
    Derived obj;
    cout << obj.f(1) << endl;
    cout << obj.f(1, 2) << endl;
}

我收到以下错误:

20:23: error: no matching function for call to 'Derived::f(int, int)'
20:23: note: candidate is:
14:13: note: virtual int Derived::f(int) const
14:13: note:   candidate expects 1 argument, 2 provided

这是为什么?这种重载是不可能的吗?

【问题讨论】:

  • @StoryTeller 确实如此。当我进行研究时,我认为这与其中一个纯虚拟功能有关,所以我想这就是我没有找到这个问题的原因。这个答案:stackoverflow.com/a/1629074/1755482 很好地解释了 name hide 现象。

标签: c++


【解决方案1】:

你需要写

class Derived : public Base {

    public:
        using Base::f;
        int f(int a) const { return a; }
};

注意using 语句。这将基类版本重新纳入范围。

【讨论】:

    【解决方案2】:

    现在,我希望这两个函数具有相同的名称,f

    你需要写

    class Derived : public Base {
    
        public:
            using Base::f;
            int f(int a) const { return a; }
    };
    

    注意using 语句。这将基类版本重新纳入范围。 [感谢@Bathsheba]

    这是为什么?这种重载是不可能的吗?

    不,由于[basic.scope.hiding¶3],不可能如原始问题中所述:

    在成员函数定义中,在块中声明名称 作用域隐藏了具有相同的类成员的声明 姓名;参见 [basic.scope.class]。 一个成员的声明 派生类隐藏了基类成员的声明 同名;参见 [class.member.lookup]。

    这个子句是关于names,而不是重载。因此,基类中是否存在其他重载无关紧要,它们都共享相同的名称,根据上面的引用隐藏。

    【讨论】:

    • 请随时将我的答案复制到此答案的顶部;用它读起来会更好。
    • 现在读起来很好 - 投赞成票!
    • @Bathsheba 我们还要否决您的答案以更加支持吗? :)
    • 哈。 @lubgr:随意 - 它不如这个答案。
    • @Bathsheba “这个答案没用”当然不适用于您的 10 秒内固定 OP 问题。
    【解决方案3】:

    您可以通过编写 using Base::f; 将 Base 的所有定义拉入范围,或者您可以明确地为 f 的某些版本编写如下内容:int f(int a, int b) const override {return Base::f(a,b);}

    class Derived : public Base {
    
    public:
        int f(int a) const { return a; }
        int f(int a, int b) const override {return Base::f(a,b);} 
    };
    

    这个answer已经提到了使用的版本:

    class Derived : public Base {
    
        public:
            using Base::f;
            int f(int a) const { return a; }
    };
    

    注意:我知道第二个版本不能在 MSVC 2010 上运行。我也知道这个编译器很古老,但只适合关心的人;)

    【讨论】:

      【解决方案4】:

      除了其他解决方案,如果您不想重新定义f,您可以使用

      显式调用基类的f
      int main() {
          Derived obj;
          cout << obj.f1(1) << endl;
          cout << obj.Base::f2(1, 2) << endl;
      }
      

      【讨论】:

        【解决方案5】:

        您也可以将它们全部设为纯,然后在派生类中覆盖它们。你可以继续使用你想要的课程。

        【讨论】:

        • 这个答案的问题是你在后代上施加了额外的工作来实际实现 f2()。最初的 f2() 不是纯虚拟的,大概是因为基本实现对于它们的许多(大多数?)用例来说已经足够了,但是如果有必要,它想让后代覆盖它。
        • @AndreKostur,您在这一点上完全正确。
        猜你喜欢
        • 2014-05-12
        • 2019-10-21
        • 1970-01-01
        • 1970-01-01
        • 2010-11-21
        • 2012-11-13
        • 2014-11-06
        相关资源
        最近更新 更多