问题描述
初步
我正在为VMEbus模块编写一个高级库。我有两个抽象层次来表示模块:
|---------------------|
| VBoard |
|---------------------|
| + VBoard( address ) |
| + Init() = 0 |
| + ... |
|---------------------|
/\ /\
/__\ /__\
|| ||__________________________
|| ||
|--------------------| |-----------------------|
| VBoardAcquisitor | | VBoardInterrupter |
|--------------------| |-----------------------|
| + AllocBuff() = 0 | | ... |
| + ... | |-----------------------|
|--------------------| /\
/\ /__\
/__\ ______ may be _____________||
|| ||
.________________________.
| |
| V1785N |
|________________________|
| + Init() override |
| + AllocBuff() override |
|________________________|
因此,每个具体模块(如上UML图中的V1785N
)都是VBoard
,并且必须覆盖Init()
函数(以及其他一些函数)。还有一些模块具有数据采集功能。对于他们来说,还有一个名为VBoardAcquisitor
的接口(抽象类),它当然也是VBoard
。 VBoardInterrupter
和具体模块之间可能会有更多的中间类(例如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;
}
如果我选择它,它会编译良好:
尽管我知道(选中)来自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