我有一个纯虚拟类,它有一个纯虚拟方法,应该是const
,但不幸的是不是。该接口位于库中,并且该类由单独项目中的其他几个类继承。
我正在尝试使用这个方法const
不会破坏兼容性(至少在一段时间内),但我找不到在非常量方法重载时产生警告的方法。
以下是我迄今为止能够制作的示例:
-
Stage 0: 变更前。仅非常量版本
Interface::doSomething()
方法存在并且它是纯虚拟的。
-
Stage 1: 过渡期间。 const 和非 const 版本
Interface::doSomething()
方法存在。它们都有一个默认实现,以便允许旧样式和新样式实现(在此阶段它们不能是纯虚拟的,因为每个继承的类只会覆盖其中一个)。 const 版本调用非常量版本是为了确保与旧实现的兼容性,非常量版本断言,因为它永远不应该被调用。
-
Stage 2:仅非常量版本
Interface::doSomething()
方法存在并且它是纯虚拟的。
In 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;
}
这是使用 3 个定义构建示例的 CMakeLists.txt 文件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)
如果能在使用已弃用的接口时发出警告,那就太好了。然而我的尝试和你的一样都失败了。我认为不幸的是,属性的设计并没有考虑到这一点。我认为属性适用于实体的名称,这意味着仅在按名称调用方法时才会收到警告。但我没有研究过这方面的标准。
所以,我怀着悲伤的心情,从这个答案 https://stackoverflow.com/a/21049735/2805305到一个稍微相关的帖子:
Tell您的用户该功能已被弃用并且不应使用,然后继续。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)