简体   繁体   中英

Default arguments on virtual methods

I'm using Clang-Tidy to inspect my code. One of the tool's messages puzzled me:

clang-tidy: Default arguments on virtual or override methods are prohibited

I get the idea when I actually use a method override. But here in my case, I want to finalize the use of the method. So I put the "final" keyword at the end of my method signature to prevent it from overriding. And to do this, we must use "virtual" keyword as well.

I don't understand why I could't use default arguments there. If I remove the "virtual/final" attributes, Clang-Tidy leave me alone, but permits to shadow the method by accident, and I don't want that.

So, is this a false-positive? A bug? Or a real problem I should take care of?

Here is the minimum reproducible example:

The case I want to avoid:

#include <iostream>

class A
{
    public:

        A () = default;
        virtual ~A () = default;

        virtual void overrideableMethod () {
            std::cout << "Method from A !" << std::endl;
        };

        void nonOverrideableMethodEvenByAccident (int a = 0) {
            std::cout << "Method from A ! V:" << a << std::endl;
        }
};

class B : public A
{
    public:

        B () : A() {}

        void overrideableMethod () override { // --> Fine.
            std::cout << "Method from B !" << std::endl;
        };

        void nonOverrideableMethodEvenByAccident (int a) { // -> Must be an error. (Omitting override here do the trick, so it's weak !)
            std::cout << "Method from B ! V:" << a << std::endl;
        };
};

int main(int argc, char const *argv[])
{
    B b{};
    b.overrideableMethod();
    b.nonOverrideableMethodEvenByAccident(9);

    /* output : 
Method from B !
Method from B ! V:9
    */

    return 0;
}

The case I want (A compiler error), but without the clang-tidy warning:

#include <iostream>

class A
{
    public:

        A () = default;
        virtual ~A () = default;

        virtual void overrideableMethod () {
            std::cout << "Method from A !" << std::endl;
        };

        virtual void nonOverrideableMethodEvenByAccident (int a = 0) final { // [WARNING] clang-tidy: Default arguments on virtual or override methods are prohibited
            std::cout << "Method from A ! V:" << a << std::endl;
        }
};

class B : public A
{
    public:

        B () : A() {}

        void overrideableMethod () override { // --> Fine.
            std::cout << "Method from B !" << std::endl;
        };

        void nonOverrideableMethodEvenByAccident (int a) { // [ERROR] error: virtual function ‘virtual void B::nonOverrideableMethodEvenByAccident(int)’ overriding final function (with or without override, great !)
            std::cout << "Method from B ! V:" << a << std::endl;
        };
};

int main(int argc, char const *argv[])
{
    B b{};
    b.overrideableMethod();
    b.nonOverrideableMethodEvenByAccident(9);

    return 0;
}

I don't understand why I could't use default arguments there.

Well, you can , but it is against the Google C++ Style Guide . The reasoning is explained in the documentation, see Default Arguments .

If you don't care about this rule, you can disable the google-default-arguments check (using --checks=-google-default-arguments ).

Another solution is to use an overloaded function without arguments instead of a function with default arguments. This does not result in the mentioned clang-tidy warning, but still does result in a compiler when (accidentally) overriding nonOverrideableMethodEvenByAccident() , as you want:

#include <iostream>

class A
{
    public:

        A () = default;
        virtual ~A () = default;

        virtual void overrideableMethod () {
            std::cout << "Method from A !" << std::endl;
        };

        virtual void nonOverrideableMethodEvenByAccident (int a) final { // No default argument!
            std::cout << "Method from A ! V:" << a << std::endl;
        }

        virtual void nonOverrideableMethodEvenByAccident (void) final { // Function without arguments
            nonOverrideableMethodEvenByAccident(0);
        }
};

class B : public A
{
    public:

        B () : A() {}

        void overrideableMethod () override {
            std::cout << "Method from B !" << std::endl;
        };

//      void nonOverrideableMethodEvenByAccident (int a) { // error: virtual function ‘virtual void B::nonOverrideableMethodEvenByAccident(int)’ overriding final function
//          std::cout << "Method from B ! V:" << a << std::endl;
//      };
};

int main(int argc, char const *argv[])
{
    B b{};
    b.overrideableMethod();
    b.nonOverrideableMethodEvenByAccident(9);
    b.nonOverrideableMethodEvenByAccident(0);

    return 0;
}

Output:

Method from B !
Method from A ! V:9
Method from A ! V:0

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