初赛
我正在为VMEbus模块编写一个高级库。我有两个抽象级别来表示模块:
|---------------------|
| VBoard |
|---------------------|
| + VBoard( address ) |
| + Init() = 0 |
| + ... |
|---------------------|
/\ /\
/__\ /__\
|| ||__________________________
|| ||
|--------------------| |-----------------------|
| VBoardAcquisitor | | VBoardInterrupter |
|--------------------| |-----------------------|
| + AllocBuff() = 0 | | ... |
| + ... | |-----------------------|
|--------------------| /\
/\ /__\
/__\ ______ may be _____________||
|| ||
.________________________.
| |
| V1785N |
|________________________|
| + Init() override |
| + AllocBuff() override |
|________________________|
因此,每个具体模块(如上述UML图中的V1785N
)都是VBoard
,必须覆盖Init()
函数(以及其他一些函数)。还有一些模块具有数据采集功能。对于他们来说,还有一个名为VBoardAcquisitor
的接口(interface)(抽象类),它当然也是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;
}
如果我可以编译的很好:VBoard
的init列表中具有一些随机地址的VBoardAcquisitor
ctorVBoard
的默认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