c++inheritancec++11derived-class

Delete virtual function from a derived class


I have a virtual base class function which should never be used in a particular derived class. Is there a way to 'delete' it? I can of course just give it an empty definition but I would rather make its attempted use throw a compile-time error. The C++11 delete specifier seems like what I would want, but

class B
{
    virtual void f();
};

class D : public B
{
    virtual void f() = delete; //Error
};

won't compile; gcc, at least, explicitly won't let me delete a function that has a non-deleted base version. Is there another way to get the same functionality?


Solution

  • It is not allowed by the standard, however you could use one of the following two workarounds to get a similar behaviour.

    The first would be to use using to change the visibility of the method to private, thus preventing others from using it. The problem with that solution is, that calling the method on a pointer of the super-class does not result in a compilation error.

    class B
    {
    public:
        virtual void f();
    };
    
    class D : public B
    {
    private:
        using B::f;
    };
    

    The best solution I have found so far to get a compile-time error when calling Ds method is by using a static_assert with a generic struct that inherits from false_type. As long as noone ever calls the method, the struct stays undefied and the static_assert won't fail.

    If the method is called however, the struct is defined and its value is false, so the static_assert fails.

    If the method is not called, but you try to call it on a pointer of the super class, then Ds method is not defined and you get an undefined reference compilation error.

    template <typename T>
    struct fail : std::false_type 
    {
    };
    
    class B
    {
    public:
        virtual void f() 
        {
        }
    };
    
    class D : public B
    {
    public:
        template<typename T = bool>
        void
        f()
        {
            static_assert (fail<T>::value, "Do not use!");
        }
    };
    

    Another workaround would be to throw an exception when the method is used, but that would only throw up on run-time.