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

|---------------------|
|        VBoard       |
|---------------------|
| + VBoard( address ) |
| + Init() = 0        |
| + ...               |
|---------------------|
         /\        /\
        /__\      /__\
         ||        ||__________________________
         ||                                  ||
|--------------------|            |-----------------------|
|  VBoardAcquisitor  |            |   VBoardInterrupter   |
|--------------------|            |-----------------------|
| + AllocBuff() = 0  |            | ...                   |
| + ...              |            |-----------------------|
|--------------------|                       /\
         /\                                 /__\
        /__\      ______ may be _____________||
         ||       ||
.________________________.
|                        |
|        V1785N          |
|________________________|
| + Init() override      |
| + AllocBuff() override |
|________________________|
因此,每个具体模块(如上述UML图中的V1785N)都是VBoard,必须覆盖Init()函数(以及其他一些函数)。还有一些模块具有数据采集功能。对于他们来说,还有一个名为VBoardAcquisitor的接口(interface)(抽象类),它当然也是VBoardVBoardInterrupter和具体模块之间可能会有更多的中间类(例如VBoard)。因此是虚拟继承。
问题
关键时刻是VBoard确实只有参数化的构造函数(参数是模块的VME地址)。而且我不希望它有其他内容(复制分配和复制ctor被删除)。但是,在C++中实现上述方案时(请参见代码部分),我得到编译错误:
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;
}
如果我可以编译的很好:
  • 调用VBoard的init列表中具有一些随机地址的VBoardAcquisitor ctor
  • 定义VBoard的默认ctor

  • 尽管我知道(选中)从VBoardAcquisitor发出的此类调用(第一种情况)将被忽略,但我不喜欢那样,因为我被迫使用某些“默认”板地址,至少从美学上讲,我对此感到不满意。
    所以我的问题是:这两个是唯一可能的“解决方案”吗?
    系统
    操作系统:Scientific Linux 7
    gcc版本:4.8.5
    注意
    请注意,在Ubuntu 18.04上,它可以使用gcc 7.5.0 正常编译,就像一样。但是我不知道为什么。

    最佳答案

    V1785N的构造函数应将地址转发给它的基类VBoardAcquisitor,基类本身会将地址转发给VBoard这是V1785N的构造函数

    V1785N( int address ) :
        VBoardAcquisitor(address)
    {}
    
    VBoardAcquisitor的构造函数
    VBoardAcquisitor(int address) :
        VBoard( address ),
        buffer( nullptr )
    { }
    
    请注意,您不应从virtual继承VBoard,因此VBoardAcquisitor的第一行看起来像
    class VBoardAcquisitor : public VBoard
    
    完整代码:https://ideone.com/YUeLtf

    10-08 11:57