【问题标题】:C++: Deprecation warning when overriding a deprecated virtual methodC ++:覆盖已弃用的虚拟方法时的弃用警告
【发布时间】:2018-02-27 15:12:00
【问题描述】:

我有一个纯虚类,它有一个纯虚方法,应该是const,但不幸的是不是。这个接口在一个库中,该类被其他几个类继承,在不同的项目中。

我正在尝试在不破坏兼容性的情况下创建此方法const(至少在一段时间内),但是当非常量方法重载时,我找不到产生警告的方法。

以下是我目前能够制作的示例:

  • 第 0 阶段:变更前。只有非常量版本的Interface::doSomething() 方法存在并且是纯虚的。
  • 第一阶段:过渡期。 Interface::doSomething() 方法的 const 和非 const 版本都存在。它们都有一个默认实现,以允许旧样式和新样式实现(在此阶段它们不能是纯虚拟的,因为每个继承的类只会覆盖其中一个)。 const 版本调用非常量版本以确保与旧实现的兼容性,非常量版本断言,因为它永远不应该被调用。
  • 第 2 阶段:仅存在 Interface::doSomething() 方法的非常量版本,并且是纯虚拟的。

Stage 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;
}

这是使用STAGE的3个定义构建示例的CMakeLists.txt文件

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)

【问题讨论】:

  • 编译器版本和C++标准?
  • 这超出了范围,但我很好奇,您为什么希望用户看到弃用警告?我想用户不必修改自己的代码以确保与新代码的兼容性,重新编译应该就足够了不是吗?
  • 最后我测试了,我收到了不推荐使用的警告here
  • @Oliv 无论用户代码如何,您的代码都会显示警告。这样,无论用户如何,您都将拥有发出警告的库。这是一件坏事。想法是在用户代码覆盖非常量方法时显示警告。
  • 也许您正在寻找“override”而不是“overload”这个词。您的代码也远非最小。

标签: c++ inheritance constants virtual deprecation-warning


【解决方案1】:

如果在使用已弃用的界面时发出警告,那就太好了。然而,我的尝试和你的一样都失败了。我认为不幸的是,属性的​​设计并未考虑到这一点。我认为属性适用于实体的名称,这意味着只有在按名称调用方法时才会收到警告。但我没有研究这方面的标准。

所以,怀着悲伤的心情,我会从this answer 中偷出一个结论,转为一个与此相关的帖子:

告诉您的用户该功能已弃用且不应使用,然后继续。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-06
    • 2015-03-23
    • 2019-07-09
    • 1970-01-01
    相关资源
    最近更新 更多