虚拟继承中最基本的 class 是否需要默认构造函数?

Is it necessary to have default ctor for the most-base class in virtual inheritance?

预赛

我正在为 VMEbus 模块编写高级库。我有两个抽象级别来表示模块:


|---------------------|
|        VBoard       |
|---------------------|
| + VBoard( address ) |
| + Init() = 0        |
| + ...               |
|---------------------|
         /\        /\
        /__\      /__\
         ||        ||__________________________
         ||                                  ||
|--------------------|            |-----------------------|
|  VBoardAcquisitor  |            |   VBoardInterrupter   |
|--------------------|            |-----------------------|
| + AllocBuff() = 0  |            | ...                   |
| + ...              |            |-----------------------| 
|--------------------|                       /\
         /\                                 /__\
        /__\      ______ may be _____________||
         ||       ||
.________________________.
|                        |
|        V1785N          |
|________________________|
| + Init() override      |
| + AllocBuff() override |
|________________________|

所以每个具体模块(如上面 UML 图中的 V1785N)都是一个 VBoard 并且必须覆盖 Init() 函数(和其他一些)。还有一些模块具有数据采集功能。对他们来说,还有另一个名为 VBoardAcquisitor 的接口(抽象 class),当然,它也是一个 VBoardVBoard 和具体模块之间可能有更多的中间 classes(如 VBoardInterrupter)。所以虚拟继承。

问题

关键时刻VBoard确实只有参数化的构造函数(参数是模块的VME地址)。而且我不希望它有其他的(复制分配和复制者被删除)。但是在 C++ 中实现上述方案时(参见 Code 部分)我得到编译错误:

Code.cpp: In constructor ‘VBoardAcquisitor::VBoardAcquisitor()’:
Code.cpp:22:29: error: no matching function for call to ‘VBoard::VBoard()’
             buffer( nullptr )
                             ^
Code.cpp:22:29: note: candidates are:
Code.cpp:8:9: note: VBoard::VBoard(int)
         VBoard( int address ) :
         ^
Code.cpp:8:9: note:   candidate expects 1 argument, 0 provided
Code.cpp:3:7: note: constexpr VBoard::VBoard(const VBoard&)
class VBoard
      ^
Code.cpp:3:7: note:   candidate expects 1 argument, 0 provided

代码

这是 MRE(使用 g++ -std=c++11 Code.cpp -o Code 编译):

#include <iostream>

class VBoard
{
    int address;

    public :
        VBoard( int address ) :
            address( address )
    { }
        virtual ~VBoard() { };

        virtual void Init() = 0;
};

class VBoardAcquisitor : virtual public VBoard
{
    int *buffer;

    public :
        VBoardAcquisitor() :
            buffer( nullptr )//problem here
    { }
        virtual ~VBoardAcquisitor() { };

        virtual void AllocBuff() = 0;
};

class V1785N : public VBoardAcquisitor
{
    public :
        V1785N( int address ) :
            VBoard( address ),
            VBoardAcquisitor()
    { }
        ~V1785N() { }

        void Init() override { std::cout << "Init\n"; }
        void AllocBuff() override { std::cout << "AllocBuff\n"; }
};


int main()
{
    V1785N adc( 0x40000000 );
    return 0;
}

如果我这样做,它编译得很好:

尽管我知道(检查过)来自 VBoardAcquisitor 的此类调用(第一种情况)将被忽略,但我不喜欢这样,因为我有点被迫使用一些“默认”板地址和至少在美学上我对此感到不舒服。

所以我的问题是:唯一可能的“解决方案”是这两个吗?

系统

OS : 科学 Linux 7

gcc 版本:4.8.5

备注

请注意,它可以在 Ubuntu 18.04 上与 gcc 7.5.0 原样 一起正常编译。但是不知道为什么。

V1785N 的构造函数应该将地址转发到它的基 class VBoardAcquisitor,它本身会将地址转发到 VBoard

这里是V1785N

的构造函数
V1785N( int address ) :
    VBoardAcquisitor(address)
{}

VBoardAcquisitor

的构造函数
VBoardAcquisitor(int address) :
    VBoard( address ),
    buffer( nullptr )
{ }

请注意,您不应该使用 virtualVBoard 继承,因此 VBoardAcquisitor 的第一行看起来像

class VBoardAcquisitor : public VBoard

完整代码:https://ideone.com/YUeLtf