开发者

C++ class member hiding rules: Design question

I've got a base class, Message, that dictates policy. I've also got derivations of that class for specific message instances.

Consider this simplified example:

template< ::size_t MessageSize >
struct Message {
    enum { size = MessageSize };
    Bits< ChunkSize > bits_[size / ChunkSize];
    // Defines behavior for the Message types
};

template< ::size_t MessageSize >
struct SmallMessage : public Message< MessageSize > {
    Bits< MessageSize > bits_;
};

// other derivations of Message...

template< class MessageType, ::size_t MessageSize >
struct MakeMessage {
    typedef typename IfElseType<
            MessageSize < ChunkSize,
            SmallMessage< MessageSize >,
            Message< MessageSize >
        >::type type;
};

If ChunkSize is 32 and I generate the following:

MakeMessage< FooMessage, 16 >
开发者_开发技巧

The Message< 16 > will result in a Bits< 32 > bits_[0]; and SmallMessage< 16 > will contain Bits< 16 > bits_ which, as I understand it, will shadow the original, zero-sized member.

There are a couple of ways I know to handle this:

  1. Declare a name other than bits_ and provide an overridden interface to that
  2. Modify SmallMessage to hide all methods of Message that deal with bits_ with local implementations
  3. Make the methods in Message virtual

My question is whether there is a benefit to either approach or if there is a better way to provide an interface to various sized memory containers as explained above.

Ultimately, I'd like to have something along the lines of:

typedef MakeMessage< FooMessage, 16 >::type message_type;
// ...
message_type message;
message.doSomethingToBits ();

Work the same regardless of what container is actually being used.


Well, as best as I can forge through this mass of template and typename, you're trying to use inheritance for composition, which is considered the wrong way to do it. SmallMessage here is not a type of Message, because as you note it doesn't support dealing with the bits_ array in the same manner.

I think the right way to do this would be to have Message as an abstract base class (important: no bits_ of any kind, probably lots of pure virtual functions), and then SmallMessage and BigMessage as implementations. Also, since you're using templates for everything anyway, the types are worked out at compile time, and there might not actually be a reason to have Message at all. As long as SmallMessage and BigMessage have the same signature, you can use message_type as you describe even if they don't have a common base class. The only reason you would need the base class Message is if you want to talk about messages more generally, using late binding. Although having the base class will also statically enforce that the signatures match right in the declaration, rather than giving strange errors... sometimes... in distant parts of the code because you misdeclared a method in one of the classes (but not the other).

It's a safe bet you also want the BigMessage::bits_ to be [(size-1) / ChunkSize + 1], which is just the ceiling rather than the floor. This way you actually have enough Bitses to fit all your bits.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜