我有一个虚拟基类函数,永远不应该在特定的派生类中使用。有没有办法'删除'它?我当然可以给它一个空的定义,但我宁愿让它尝试使用抛出编译时错误。 C ++ 11 delete
说明符似乎是我想要的,但
class B
{
virtual void f();
};
class D : public B
{
virtual void f() = delete; //Error
};
不会编译; gcc,至少,明确地不允许我删除具有未删除的基本版本的函数。还有其他方法可以获得相同的功能吗?
答案 0 :(得分:29)
标准不允许这样做,但您可以使用以下两种解决方法之一来获得类似的行为。
第一种方法是使用using
将方法的可见性更改为私有,从而阻止其他人使用它。该解决方案的问题是,在超类的指针上调用该方法不会导致编译错误。
class B
{
public:
virtual void f();
};
class D : public B
{
private:
using B::f;
};
到目前为止,我发现在调用D
方法时遇到编译时错误的最佳解决方案是使用static_assert
来继承自false_type
的泛型结构。只要没有人调用该方法,结构就会保持不变,static_assert
不会失败。
如果调用该方法,则定义结构并且其值为false,因此static_assert
失败。
如果方法未被调用,但是你试图在超类的指针上调用它,那么D
的方法没有定义,你得到{{1}编译错误。
undefined reference
另一种解决方法是在使用该方法时抛出异常,但这只会摒弃运行时。
答案 1 :(得分:10)
标准不允许您出于某种原因删除派生类中基类的任何成员:
这样做会破坏继承,特别是“is-a”关系。
由于相关原因,它不允许派生类定义在基类中删除的函数:
钩子不再是基类合约的一部分,因此它阻止你依赖之前不再持有的担保。
如果你想变得棘手,你可以强制出错,但它必须是链接时而不是编译时:
声明成员函数但不要定义它(虽然这不是100%保证适用于虚函数)
最好还看一下早期警告__attribute__ ((deprecated))
的GCC已弃用属性
有关详细信息和类似的MS魔术:C++ mark as deprecated
答案 2 :(得分:2)
"我有一个虚拟基类函数,永远不应该在特定的派生类中使用。"
在某些方面,这是一个矛盾。虚函数的重点是提供基类提供的契约的不同实现。你要做的是打破合同。 C ++语言旨在阻止您这样做。这就是为什么它会强制您在实例化对象时实现纯虚函数。这就是为什么它不会让您删除部分合同。
正在发生的是好事。它可能会阻止您实施不恰当的设计选择。
<强>然而强>
有时可能适合使用无效的空白实现:
void MyClass::my_virtual_function()
{
// nothing here
}
或者是一个返回&#34;失败的空白实现&#34;状态:
bool MyClass::my_virtual_function()
{
return false;
}
这完全取决于你想要做什么。也许如果你能提供更多关于你想要达到的目标的信息,那么有人可以指出你正确的方向。
修改强>
如果你考虑一下,为了避免为特定的派生类型调用函数,调用者需要知道它调用的是什么类型。调用基类引用/指针的重点是,您不知道哪个派生类型将接收该调用。
答案 3 :(得分:0)
您可以做的只是在派生实现中抛出异常。例如,Java Collections框架相当过分:当对不可变的集合执行更新操作时,相应的方法只会抛出UnsupportedOperationException
。您可以在C ++中执行相同的操作。
当然,这只会在运行时显示恶意使用该功能;不是在编译时。但是,使用虚方法,由于多态性,无论如何都无法在编译时捕获此类错误。 E.g:
B* b = new D();
b.f();
在此,您将D
存储在B*
变量中。因此,即使有一种方法告诉编译器您不允许在f
上调用D
,编译器也无法在此处报告此错误,因为它只看到{{1 }}
答案 4 :(得分:0)
我有一个虚拟基类函数,永远不应该在特定的派生类中使用。
C ++ 11提供了一个关键字final
,可防止虚拟函数被覆盖。
看:http://en.cppreference.com/w/cpp/language/final。
class B
{
virtual void f() final;
};
class D : public B
{
// virtual void f(); // a compile-time error
// void f() override; // a compile-time error
void f(); // non-virtual function, it's ok
};