问题 创建虚拟功能的纯虚函数是危险的吗?


让我们假设我们有一个抽象类 NonEditableSuperBase 我们从中创建另一个抽象类 MyBase

第一堂课 NonEditableSuperBase 有一个虚拟功能(非纯虚拟)。但是,如果有人创建了一个派生自的类,我想强制它 MyBase,他/她必须为上述功能提供实施。

因此,我的想法是将函数定义为纯虚拟 MyBase

我的问题: 这是个坏主意 鉴于它只是虚拟的 NonEditableSuperBase

例:

//NonEditableSuperBase.h
class NonEditableSuperBase
{
  ...
  public:
    virtual int someMethod(); //It has an implementation, suppose {return 42;}
};

//MyBase.h
class MyBase: public NonEditableSuperBase
{
  public:
     explicit MyBase();       
     virtual ~MyBase() = default;       
     virtual int someMethod() = 0;  //I make it pure virtual
};

//MyBase.cpp
MyBase::MyBase() : NonEditableSuperBase() { }

//Now someone creates a derived class from MyBase.
class SuperDerived : public MyBase
{
  public:
    explicit SuperDerived();
    int someMethod(); //The user must create an implementation of the function
};

更新: 作为一个例子,在我的情况下,我想从中创建一些派生类 QAbstractTableModel Qt框架的类。要重用一些代码,我想创建一个中间抽象类。

QAbstractTableModel <- MyAbstractModel <- MyModelA (or MyModelB ... etc).

但是,我想确保模型(MyModelA,MyModelB)重新实现QAbstractTableModel的一些虚函数(如:: index()函数),因为MyAbstractModel的一些额外方法需要引物函数的特定实现。


7832
2018-03-31 14:55


起源

这是一个公平的问题,但不适用于StackOverflow,它不处理编程风格问题。如果你定义了一个基本方法,就必须想知道在中间类中使它无效的情况。 - Malcolm McLean
这是完全可能的,并实现你想要的。没什么危险的。它是否是一种好的风格是非常主观的。 - Jesper Juhl
如果someMethod在SuperDerived中被注释掉/未定义,则gcc 4.9表示SuperDerived实例化时出错(如果Derived是MyBase),如@JesperJuhl所述 - Laurent G
您是否打算让MyBase使用NonEditableSuperBase的私有继承? - Adrian McCarthy
我会在NonEditableSuperBase中保护虚拟 - Mateusz Wojtczak


答案:


ISO IEC 14882 2014

§10.4说:

5 [注意:抽象类可以从非抽象的类派生,纯虚函数可以   覆盖一个不纯的虚函数。 - 尾注]

所以完全有可能做到这一点。

用例示例:

您可以拥有一个基本类型,它是作为具体类型(基类)实现的。现在,对于子类型,我们可能需要进一步的其他信息。因此,我们可以拥有一个抽象的中间对象来满足我们的需求。


11
2018-03-31 16:13





[我假设MyBase的目的是公开派生自NonEditableSuperBase,这不是问题中的代码示例实际上做的。]

它本身并不危险,但考虑到源自MyBase的SuperDerived类可以明确选择使用NonEditableSuperBase实现。

class SuperDerived : public MyBase {
  public:
    using NonEditableSuperBase::someMethod;
    // Or, explicitly:
    // int someMethod() override { return NonEditableSuperBase::someMethod(); }
};

这满足了MyBase强加的纯虚拟要求,但就像MyBase没有那个要求一样。你已经成为SuperDerived的作者了 某物,但实际上并没有阻止他们使用最终基类的实现。


2
2018-03-31 16:16



首先,是的,我想公开派生自NonEditableSuperBase,我已经更正了代码,谢谢。其次,我并不打算阻止用户使用NonEditableSuperBase方法,只是提醒他们必须实现它们(如果他们按照你所知的那样知道他们在做什么) - pablo_worker
查看有关在基类中具有实现的纯虚方法的其他问题。这实现了相同的效果:提供合理的默认行为,同时要求派生类的实现者有意识地选择获取默认行为。 stackoverflow.com/questions/2089083/... - Adrian McCarthy