C ++ Diamond Inheritance

I have a Channel class with two two properties, direction and size, which are fixed during construction. Direction can take only one of two values: forward (1) or backward (-1). Size can take any value, but there is a physically significant difference between 0 and any non-zero value.

I would like to write functions that accept channel objects with known values ​​for direction and / or size, and I decided to implement this using derived classes:

Channel | ----------------------------------------------- | | | | ForwardChannel BackwardChannel ZeroChannel NonzeroChannel | | | | | ---------------- ... | | | | BackwardZeroChannel | | | --------------------------------- | ForwardZeroChannel 

Obviously, I did not draw all the permutations.

I tried to implement it like this

 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) ... } 

Creating ForwardChannel and ZeroChannel instances works great. When launched, ForwardZeroChannel calls only the default constructor for a channel that does not set values. I have to add Channel (1, 0) to the list of initializers:

 class ForwardZeroChannel: public ForwardChannel, ZeroChannel { ForwardZeroChannel() : Channel(0, 1), ForwardChannel(0), ZeroChannel(1) ... } 

but that seems to have surpassed some of the acquisition goals from ForwardChannel and ZeroChannel. Is there a better way to do this?

+4
source share
3 answers

how about (following you need C ++ 11, but it can be ported to C ++ 99 (except for "using the template"):

 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; } 
+1
source
  class ForwardZeroChannel: public ForwardChannel, ZeroChannel { ForwardZeroChannel() : Channel(0, 1), ForwardChannel(0), ZeroChannel(1) ... } 

According to Herb Shutter, it is the duty of an object of a derived class to initialize sub-objects of the parent class by calling constructors (in the case of virtual derivation), otherwise the compiler will call the constructor of the parent sub-objects.

+1
source

Another option would be to create a Channel interface with pure virtual size and direction functions and a default constructor. Then ForwardChannel or ZeroChannel come from the channel and implement certain functions.

 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(); } 
+1
source

Source: https://habr.com/ru/post/1501098/


All Articles