Правила сокрытия членов класса C ++: вопрос разработки - PullRequest
2 голосов
/ 10 мая 2011

У меня есть базовый класс, Message, который определяет политику.Я также получил производные этого класса для конкретных экземпляров сообщений.

Рассмотрим этот упрощенный пример:

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;
};

Если ChunkSize равно 32, и я генерирую следующее:

MakeMessage< FooMessage, 16 >

Message< 16 > приведет к Bits< 32 > bits_[0];, а SmallMessage< 16 > будет содержать Bits< 16 > bits_, который, насколько я понимаю, будет затенять исходный элемент нулевого размера.

Я знаю несколько способов справиться с этим:

  1. Объявить имя, отличное от bits_, и предоставить переопределенный интерфейс для этого
  2. Изменить SmallMessage скрыть все методы Message, которые имеют дело с bits_ с локальными реализациями
  3. Сделать методы в Message virtual

Мой вопрос: есть ли пользалибо подходить, либо, если есть лучший способ предоставить интерфейс для контейнеров памяти различного размера, как описано выше.

В конечном счете, я хотел бы иметь что-то вроде:

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

Работайте одинаково, независимо от того, какой контейнер на самом деле используется.

1 Ответ

0 голосов
/ 10 мая 2011

Что ж, как я могу пробиться через эту массу template и typename, вы пытаетесь использовать наследование для композиции, что считается неправильным способом сделать это. SmallMessage здесь не тип Message, потому что, как вы заметили, он не поддерживает работу с массивом bits_ таким же образом.

Я думаю, что правильным способом для этого было бы иметь Message в качестве абстрактного базового класса (важно: нет bits_ любого вида, возможно, множество чистых виртуальных функций), а затем SmallMessage и BigMessage как реализации. Кроме того, поскольку вы все равно используете шаблоны для всех типов, они разрабатываются во время компиляции, и на самом деле не может быть причины иметь Message вообще. Пока SmallMessage и BigMessage имеют одинаковую подпись, вы можете использовать message_type, как вы описываете, даже если у них нет общего базового класса. Единственная причина, по которой вам нужен базовый класс Message, заключается в том, что вы хотите говорить о сообщениях более широко, используя позднюю привязку. Хотя наличие базового класса также будет статически обеспечивать соответствие сигнатур прямо в объявлении, вместо того, чтобы выдавать странные ошибки ... иногда ... в удаленных частях кода, потому что вы ошибочно объявили метод в одном из классов (но не в прочее).

Безопасная ставка, вы также хотите, чтобы BigMessage::bits_ было [(size-1) / ChunkSize + 1], что является просто потолком, а не полом. Таким образом, у вас на самом деле будет достаточно Bits, чтобы вместить все ваши биты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...