简体   繁体   中英

C++ same name for non-virtual function in derived class conflicts with `final` specifier

This has the feeling of a complete newbie question, but why does the following code not compile when the final specifier is used for B::operator() ?

struct A
{
    virtual void operator()() const = 0;
};

// the CRTP-component is not really necessary here
// but it possibly makes more sense in that it could be applied like this in reality
//
template<typename Derived>
struct B : A
{
    virtual void operator()() const override final
    {
        static_cast<Derived const&>(*this).operator()();
    }
};

struct C : B<C>
{
    void operator()() const
    {
        //do something
    }
};

int main()
{
    C()();
}

G++ prints the following error message :

main.cpp:17:14: error: virtual function 'virtual void C::operator()() const'
         void operator()() const
              ^
main.cpp:9:22: error: overriding final function 'void B<Derived>::operator()() const [with Derived = C]'
         virtual void operator()() const override final
                      ^

I would have thought it works as the non-virtual C::operator() does not override the virtual functions in its base classes? How can I bring this to work (--without changing the name of C::operator() )?


: As pointed out by several users, the answer is simply that the virtual -keyword in the derived class is redundant (whereas I thought leaving it out would prevent from inheriting). :正如几个用户所指出的,答案很简单,派生类中的virtual -keyword是多余的(而我认为将其保留会阻止继承)。 However, the goal I had in asking this -- namely -- can be solved by using a non-virtual operator[] throughout and couple classes A and B by a virtual function apply : 可以通过在整个过程中使用非虚拟operator[]来解决,并通过一个虚拟函数apply耦合类AB

struct A
{
    void operator()() const
    {
        this->apply();
    }

protected:
    virtual void apply() const = 0;
};

template<typename Derived>
struct B : A
{
    void operator()() const
    {
        static_cast<Derived const&>(*this).operator()();
    }

protected:
    virtual void apply() const override final
    {
        this->operator()();
    }
};

struct C : B<C>
{
    void operator()() const
    {
        //do something
    }
};

int main()
{
    C()();
}

If a function is declared virtual in a base class, then a function declared with the same name and parameter list is implicitly virtual in derived classes, whether or not you use the virtual keyword. You cannot make C::operator()() non-virtual.

A function in a derived class with the same signature as a virtual function in a base class overrides that virtual function from the base class. That makes it a virtual function, even if/though the declaration in the derived class doesn't use the virtual key word.

That can't be changed, so if you really need to have a function with the same name in a derived class that doesn't override the virtual function from the base class (and in the process, become virtual itself and in this case, violate the final in B ) you'll need to change the signature of the function in the derived class. That can mean a different name, different parameter list, or different qualifiers. I'd treat the latter two with extreme caution though--the compiler will be able to sort out the mess you've made, but many human readers may (very easily) be surprised.

If I were reviewing such code, I'd probably cite this as a problem, and the author would need to provide very solid reasoning for why it was truly necessary to get it approved.

As an override (because it has the same signature as the virtual function in a base class), the override conflicts with the final specified in its base class.

One fix (or rather workaround) is to give that function a defaulted argument, so that it has a different type and hence not an override, and a better approach is to fix the design.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM