C++ 钻石般的传承
C++ Diamond-like inheritance
我有一个类通道,有两个属性,方向和大小,在施工过程中是固定的。方向只能采用两个值之一,向前 (1) 或向后 (-1)。Size 可以采用任何值,但 0 和任何非零值之间存在物理上有意义的区别。
我希望能够编写接受具有已知方向和/或大小值的 Channel 对象的函数,我想使用派生类来实现这一点:
Channel
|
-----------------------------------------------
| | | |
ForwardChannel BackwardChannel ZeroChannel NonzeroChannel
| | | |
| ---------------- ...
| | |
| BackwardZeroChannel |
| |
---------------------------------
|
ForwardZeroChannel
显然,我没有绘制所有排列。
我尝试这样实现它
class Channel {
Channel(int direction, int size) { ... };
...
}
class ForwardChannel: public virtual Channel {
ForwardChannel(int size) : Channel(1, size) { ... }
...
}
class ZeroChannel: public virtual Channel {
ZeroChannel(int direction) : Channel(direction, 0) { ... }
...
}
class ForwardZeroChannel: public ForwardChannel, ZeroChannel {
ForwardZeroChannel() : ForwardChannel(0), ZeroChannel(1)
...
}
实例化转发通道和零通道工作正常。实例化 ForwardZeroChannel 仅调用不设置值的 Channel 的默认构造函数。我必须将通道(1, 0)添加到初始值设定项列表中:
class ForwardZeroChannel: public ForwardChannel, ZeroChannel {
ForwardZeroChannel() : Channel(0, 1), ForwardChannel(0), ZeroChannel(1)
...
}
但这似乎违背了从ForwardChannel和ZeroChannel衍生出来的一些目的。有没有更好的方法
呢
(以下需要 C++11,但它可以移植到 C++99("模板使用"除外):
class Channel {
public:
virtual ~Channel();
protected:
Channel(int direction, int size);
};
template<bool forward, bool zero>
class ChannelT : public Channel {
public:
template <bool b = zero, typename T = typename std::enable_if<b>::type>
ChannelT() : Channel(forward ? 1 : 0, 0) {}
template <bool b = zero, typename T = typename std::enable_if<!b>::type>
explicit ChannelT(int size) : Channel(forward ? 1 : 0, size) { assert(size != 0); }
};
template <bool zero> using ForwardChannel = ChannelT<true, zero>;
using ForwardZeroChannel = ChannelT<true, true>;
using ForwardNonZeroChannel = ChannelT<true, false>;
// And so on for the 5 other types...
int main() {
ForwardZeroChannel forwardZeroChannel;
ForwardNonZeroChannel forwardNonZeroChannel(42);
return 0;
}
class ForwardZeroChannel: public ForwardChannel, ZeroChannel {
ForwardZeroChannel() : Channel(0, 1), ForwardChannel(0), ZeroChannel(1)
...
}
根据"Herb Shutter",派生类对象负责通过调用构造函数(在虚拟派生情况下)来初始化父类子对象,否则编译器将通过调用父子对象的构造函数。
另一种选择是将Channel
制作为具有纯虚拟大小和方向函数以及默认构造函数的接口。然后ForwardChannel
或ZeroChannel
从通道派生并实现特定功能。
struct Channel
{
virtual int direction() const = 0;
virtual int size() const = 0;
virtual ~Channel() {}
};
struct ForwardChannel: virtual public Channel
{
virtual int direction() const override { return 1; }
};
struct ZeroChannel: virtual public Channel
{
virtual int size() const override { return 0; }
};
struct ForwardZeroChannel: public ForwardChannel, public ZeroChannel
{
};
int main()
{
ForwardZeroChannel z;
return z.size() + z.direction();
}
相关文章:
- 什么是钻石问题?是一系列问题还是特定问题?
- 钻石继承虚拟成员铸造与指针
- 接口的钻石继承(C++)
- 在钻石问题的求解中,为什么要虚拟地继承两次grand-parent类
- C++如何解决钻石问题?
- c++ 中的函数重载如何在没有钻石继承的情况下工作?
- 多个虚拟(钻石)继承
- C++解决没有虚拟继承的钻石继承问题
- 多种继承C 的钻石问题
- 如何调用所有基本类的复制构造函数,以在C 中复制钻石继承中最派生的类对象
- 假设钻石继承打破了C++的封装是否正确?
- C++多个钻石继承和纯虚函数
- 如何解决钻石问题的这种歧义
- 解决QT类的特定C 钻石问题
- 在C++中尝试基于用户确定的宽度打印钻石
- 学习传承
- 虚拟继承如何解决 c++ 中的多重继承(钻石)?它将走哪条路
- 首选钻石继承中一个类的变量
- C++ 钻石般的传承
- 钻石传承