C ++: failure warning when overriding an obsolete virtual method

I have a pure virtual class that has a pure virtual method that should be const, but unfortunately this is not the case. This interface is in the library, and the class is inherited by several other classes in separate projects.

I am trying to make this method constwithout interruption of compatibility (at least for some time), but I cannot find a way to create a warning when the non-console method is overloaded.

The following is an example of what I have been able to do so far:

  • Stage 0 : before the change. There is only a non-const version Interface::doSomething(), and it is pure virtual.
  • Stage 1 : during the transition period. There are both constant and non-constant versions of the method Interface::doSomething(). Both of them have a default implementation to allow both the old style and the new style implementations (they cannot be pure virtual at this stage, since each inherited class overrides only one of them). The const version supports the non-content version to ensure compatibility with older implementations, the non-content version claims, since it should never be called.
  • Stage 2 : there is only a non-content version of the method Interface::doSomething()and it is pure virtual.

1 , , Interface::doSomething(), , , , Stage 2, . , . , GCC, Clang. , , - (, final), , . ?

#include <iostream>
#include <cassert>

class Interface
{
public:
    virtual ~Interface() = default;

// callDoSomething method:
// - stage 0: non const
// - stage 1-2: const
#if (STAGE == 0)
    void callDoSomething() { doSomething(); }
#else
    void callDoSomething() const { doSomething(); }
#endif

protected:

// non-const doSomething() method:
// - stage 0: pure virtual
// - stage 1: virtual with assert in default implementation (should never be called)
// - stage 2: removed
#if (STAGE == 0)
    virtual void doSomething() = 0;
#elif (STAGE == 1)
    [[deprecated("Overload const version instead")]]
    virtual void doSomething()
    {
        assert(false);
    }
#endif

// const doSomething() method
// - stage 0: N/A
// - stage 1: virtual with default implementation (calls the non-const overload)
// - stage 2: pure virtual
#if (STAGE == 1)
    virtual void doSomething() const
    {
        std::cout << __PRETTY_FUNCTION__ << '\n';
        std::cout << "  calling non const version\n";
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
        const_cast<Interface*>(this)->doSomething();
#pragma GCC diagnostic pop
    }
#elif (STAGE == 2)
    virtual void doSomething() const = 0;
#endif
};


// Old style implementation: non-const doSomething()
// Allowed only in stages 0 and 1
#if (STAGE == 0 || STAGE == 1)
class Implementation_old : public Interface
{
public:
    virtual ~Implementation_old() = default;

protected:
    virtual void doSomething() override
    {
        std::cout << __PRETTY_FUNCTION__ << '\n';
    }
};
# endif


// Old style implementation: const doSomething()
// Allowed only in stages 1 and 2
#if (STAGE == 1 || STAGE == 2)
class Implementation_new : public Interface
{
public:
    virtual ~Implementation_new() = default;

protected:
    virtual void doSomething() const override
    {
        std::cout << __PRETTY_FUNCTION__ << '\n';
    }
};
#endif


int main(int argc, char *argv[])
{
    Interface* iface = nullptr;

#if (STAGE == 0 || STAGE == 1)
    iface = new Implementation_old;
    iface->callDoSomething();
    delete iface;
#endif

#if (STAGE == 1)
    std::cout << "-------------------\n";
#endif

#if (STAGE == 1 || STAGE == 2)
    iface = new Implementation_new;
    iface->callDoSomething();
    delete iface;
#endif

    iface = nullptr;

    return 0;
}

CMakeLists.txt , 3 STAGE

cmake_minimum_required(VERSION 3.5)
project(test_deprecate_non_const)

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

add_executable(main_stage_0 main.cpp)
target_compile_definitions(main_stage_0 PRIVATE STAGE=0)

add_executable(main_stage_1 main.cpp)
target_compile_definitions(main_stage_1 PRIVATE STAGE=1)

add_executable(main_stage_2 main.cpp)
target_compile_definitions(main_stage_2 PRIVATE STAGE=2)
+4
1

. , . , , , . , , , . .

, , :

, , .

+2

Source: https://habr.com/ru/post/1694185/


All Articles