4

I have a class Channel 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 meaningful distinction between 0 and any nonzero value.

I'd like to be able to write functions that accept Channel objects with known values for the direction and/or size, and I thought to implement this using derived classes:

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

Obviously I didn't draw all of the permutations.

I tried implementing it as so

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

Instantiating ForwardChannel and ZeroChannel works fine. Instantiating ForwardZeroChannel calls only the default constructor for Channel which doesn't set the values. I have to add Channel(1, 0) to the initializer list:

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

but that seems to defeat some of the purpose of deriving from ForwardChannel and ZeroChannel. Is there a better way of doing this?

4

3 回答 3

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

根据“Herb Shutter”,派生类对象有责任通过调用构造函数(在虚拟派生情况下)初始化父类子对象,否则编译器将调用父子对象的构造函数。

于 2013-09-07T19:03:29.473 回答
1

怎么样(需要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;
}
于 2013-09-07T19:04:28.570 回答
1

另一种选择是制作Channel一个具有纯虚拟大小和方向功能以及默认构造函数的接口。然后ForwardChannel还是ZeroChannel从Channel派生出来,实现具体的功能。

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();
}
于 2013-09-07T19:24:12.800 回答