微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

虚拟继承中最基本的类是否必须具有默认ctor?

如何解决虚拟继承中最基本的类是否必须具有默认ctor?

初步

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


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

因此,每个具体模块(如上UML图中的V1785N)都是VBoard,并且必须覆盖Init()函数(以及其他一些函数)。还有一些模块具有数据采集功能。对于他们来说,还有一个名为VBoardAcquisitor的接口(抽象类),它当然也是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(第一种情况)的呼叫会被忽略,但我不喜欢那样,因为我被迫使用一些“认”板卡地址,至少从美学上来说,我对此感到不舒服。

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

系统

OS:科学版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的{​​{1}},因此VBoard的第一行看起来像

VBoardAcquisitor

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。