代码之家  ›  专栏  ›  技术社区  ›  Luke Nicholson

是否可以强制超类中的非常量虚方法优先于子类中同名的常量方法?

  •  1
  • Luke Nicholson  · 技术社区  · 6 年前

    考虑以下类定义:

    class foo {
      virtual absl::Span<const Input *const> GetInputs() const = 0;
    
      virtual absl::Span<Input *const> GetInputs() {
        auto mutable_inputs = GetMutableInputs();
        return absl::MakeSpan(mutable_inputs.begin(), mutable_inputs.end());
      }
    }
    
    class bar : public foo {
      absl::Span<const Input *const> GetInputs() const override {
        return absl::MakeConstSpan(inputs_);
      }
    }
    

    呼叫时 bar.GetInputs() 似乎找到的唯一实现是返回一系列常量输入的实现。如果我有一个bar实例,并且想要创建一个非常量输入的范围,那么我必须将bar转换为foo,然后调用 GetInputs

    如果我把bar投给foo,然后打电话 获取输入 ,然后我可以将结果分配给一系列非常量输入。为什么编译器无法用正确的返回类型标识继承的非常量方法?有没有办法让子类识别该方法?

    换言之,是否有办法编译以下代码:

    absl::Span<Input *const> tmp = bar.GetInputs()
    
    2 回复  |  直到 6 年前
        1
  •  1
  •   Chris Uzdavinis    6 年前

    如果我理解你的问题,它与虚函数或const的“优先级”无关,而是一个很老的“名称隐藏”。

    #include <iostream>
    class Base {
    public:
        virtual void f(int)    { std::cout << "Base(int)\n"; }
        virtual void f(double) { std::cout << "Base(double)\n"; }
    };
    
    class Derived : public Base {
    public:
        virtual void f(double) { std::cout << "Derived(double)\n"; }
    };
    
    int main() {
        Derived d;
        int x=0;
        d.f(x);
    }
    

    输出:派生(双精度)

    问题是,名称查找并不像您所期望的那样工作。 对于给定的作用域,它搜索名称以构建重载集。在派生的上下文中,只有一个f(),因此当找到它时,编译器 停止进一步搜索更多重载

    它查找派生(double),这是整个重载集,因此它被选中。当您将派生类强制转换为对基的引用,然后调用某个对象时,会考虑这两个函数(在基中声明),重载解析会选择最佳匹配。

    现在,通常情况下,对于多态类型,您使用的对象是指向基的指针/引用,因此这不是问题。但是如果您直接调用派生类(可能是从派生类的成员内部调用?)然后会出现派生声明隐藏基名称的问题。

    要使基名在派生类中可见,很容易:

    class Derived : public Base {
    public:
        using base::f; // <<<<<<<< just add this
        virtual void f(double) { std::cout << "Derived(double)\n"; }
    };
    
        2
  •  1
  •   Arkady Godlin    6 年前

    您应该添加

    using foo::GetInputs;
    

    在里面 bar 类以公开基类函数。

    如果对象为非常量,则可以调用基类函数