【发布时间】:2021-02-02 07:41:15
【问题描述】:
预赛
我正在为 VMEbus 模块编写一个高级库。我有两个抽象级别来表示模块:
|---------------------|
| VBoard |
|---------------------|
| + VBoard( address ) |
| + Init() = 0 |
| + ... |
|---------------------|
/\ /\
/__\ /__\
|| ||__________________________
|| ||
|--------------------| |-----------------------|
| VBoardAcquisitor | | VBoardInterrupter |
|--------------------| |-----------------------|
| + AllocBuff() = 0 | | ... |
| + ... | |-----------------------|
|--------------------| /\
/\ /__\
/__\ ______ may be _____________||
|| ||
.________________________.
| |
| V1785N |
|________________________|
| + Init() override |
| + AllocBuff() override |
|________________________|
所以每个具体模块(如上面 UML 图中的V1785N)都是一个VBoard,并且必须覆盖Init() 函数(以及其他一些函数)。还有一些具有数据采集功能的模块。对于他们来说,还有另一个名为VBoardAcquisitor 的接口(抽象类)当然也是VBoard。在VBoard 和具体模块之间可能有更多的中间类(如VBoardInterrupter)。所以虚拟继承。
问题
关键时刻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的初始化列表中调用VBoardctor带有一些随机地址 - 定义
VBoard的默认ctor
虽然我知道(检查过)来自VBoardAcquisitor(第一种情况)的此类调用将被忽略,但我不喜欢这样,因为我不得不使用一些“默认”板地址,至少在美学上我对此感到不舒服。
所以我的问题是:唯一可能的“解决方案”是这两个吗?
系统
操作系统:科学 Linux 7
gcc 版本:4.8.5
注意
请注意,它可以在 Ubuntu 18.04 上使用 gcc 7.5.0按原样 正常编译。但我不知道为什么。
【问题讨论】:
-
您是否打算直接默认构造 VBoardAcquisitors?在示例代码中,您构造了一个 V1785N,它将一个(可能有意义的)地址传递给 VBoard 并默认构造一个 VBoardAcquisitor。但是 VBoardAcquisitor 是从 VBoard 继承的,对吧?那么为什么不将它传递给 VBoardAcquisitor 并使用其成员初始化列表来设置 VBoard?是否可能有一些类多次从 VBoardAcquisitor 继承但只想使用单个底层虚拟 VBoard?
-
@NathanPierson,我认为你似乎是对的。
-
VBoardInterrupter 是否应该成为 VBoard 本身,还是应该对 VBoard 采取行动?很可能 VBoardInterrupter 不需要从 VBoard 继承和/或 VBoard 的具体实例不需要从 VBoardInterrupter 继承,例如,如果 VBoardInterrupter 具有代表它正在中断的 VBoard 的 VBoard* 成员变量。
-
@NathanPierson,是的,我现在什至不知道这个类的实现,tbh (: 。但本质上,VME 板本身就是一个中断器。可能,这个问题不处理虚拟继承。但无论如何,我想改变一切为时已晚。
标签: c++ inheritance default-constructor virtual-inheritance