从派生类中删除虚函数

时间:2014-07-07 11:47:37

标签: c++ inheritance c++11 derived-class

我有一个虚拟基类函数,永远不应该在特定的派生类中使用。有没有办法'删除'它?我当然可以给它一个空的定义,但我宁愿让它尝试使用抛出编译时错误。 C ++ 11 delete说明符似乎是我想要的,但

class B
{
    virtual void f();
};

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

不会编译; gcc,至少,明确地不允许我删除具有未删除的基本版本的函数。还有其他方法可以获得相同的功能吗?

5 个答案:

答案 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
};