【问题标题】:How to fix overloaded function with different signature如何修复具有不同签名的重载函数
【发布时间】:2018-07-16 07:04:30
【问题描述】:

我正在集成其他开发人员的代码库。我偶然发现了以下情况:

#include <iostream>

struct A
{
    virtual void test(int a)
    {
        std::cout << "A::test(" << a << ')' << std::endl;
    }
};

struct B : public A
{
    // using A::test;

    void test(int a, int b)
    {
        std::cout << "B::test(" << a << ", " << b << ')' << std::endl;
        A::test(a);
    }
};

int main()
{
    B b;
    b.test(1, 2);
}

使用g++ -Wall 编译此代码不会出现警告,但使用clang++ -Wall 我得到:

x.cpp:15:11: warning: 'B::test' hides overloaded virtual function [-Woverloaded-virtual]
        void test(int a, int b)
             ^
x.cpp:5:19: note: hidden overloaded virtual function 'A::test' declared here: different number of parameters (1 vs 2)
        virtual void test(int a)
                     ^
1 warning generated.

两种情况下的输出都是:

B::test(1, 2)
A::test(1)

如何解决这种情况?对我来说没有明确的路径,因为不清楚原始程序员的意图是什么。

  • 可能是他想在B 实例中隐藏A::test 的版本,并且只使用带有附加参数的版本(我认为这里就是这种情况)。
  • 但我可以使用(注释掉的)using A::test 语句来消除警告,但调用b.test(1) 将直接调用A::test,忽略过载。很可能原作者也不想在B 类中公开A::test
  • 另一个想法是添加缺少的重载并使其引发异常,例如(在B):

    void test(int a)
    {
        throw std::logic_error("unsupported function overload");
    }
    

    但这感觉很糟糕,因为它是运行时的事情,我认为编译时应该已经出现错误或警告。

是否有一种规范的方法可以重载A::test 并以不需要使用-Wno-overloaded-virtual 的方式消除警告?

当前解决方案

class B: public A
{
    private:
    using A::test;

    public:
    ...
};

这消除了警告,如果调用b.test(1) 将给出错误。当然,它仍然可以调用A::test...

【问题讨论】:

  • 由于没有重写函数,所以不需要创建为virtual
  • 为什么不问问原作者的意图呢?
  • @liliscent 好吧,我不知道他的意图(100% 确定),但我有一个想法(
  • @Olaf Dietsche 他目前不可用:/ 否则我当然会有 :)
  • @UKMonkey 接口就是合约。通过公开从 A 派生,您承诺维护 A 的合同。破坏A::test 会破坏承诺,所以不要这样做

标签: c++ overloading clang++ derived-class


【解决方案1】:

一种可能的解决方案或变通方法可能是将A::test 拉入B 的范围内,例如

struct B : A
{
    using A::test;
    ...
};

然后你可以使用普通的test(a) 并且应该调用A::test

【讨论】:

  • 我对此表示赞同,因为尽管 OP 已经提到了这种方法,但它确实是正确的答案。万一最初的程序员打算隐藏该函数,父类接口契约的缩小表明某处的设计决策不佳,这是应该修复的事情,以便不再需要隐藏。跨度>
【解决方案2】:

虽然您可以在 B 中将 test(int) 设为私有,这将删除警告;你最终会遇到这样的情况,有人可以将它作为“A”对象简单地传递,然后无论如何调用 test(int) 。我不会担心原始工程师的意图,因为有一种方法可以调用 test(int) 并确保它的作用是有意义的;即使这意味着使用时抛出或编译失败。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-11
    • 2021-10-16
    • 2011-05-11
    • 1970-01-01
    • 1970-01-01
    • 2019-12-19
    相关资源
    最近更新 更多