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:
- Declare a name other than
bits_
and provide an overridden interface to that - Modify
SmallMessage
to hide all methods ofMessage
that deal withbits_
with local implementations - 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 Bits
es to fit all your bits.
精彩评论