2013-07-06 4 views
2

У меня есть класс, который я бы хотел определить для оператора []. Класс содержит последовательный пакет (вместе со связанными функциями для работы с указанным пакетом). Я хотел бы иметь пользователь имеет возможность сделать что-то вроде этого ...Оператор C++ [] Перегрузка SNAFU

MyClass packet; 
uint8_t byte = packet[3]; // get third byte of packet 

Я хотел бы запретить пользователю делать это ...

packet[3] = 0xAA; // this breaks encapsulation for my class :(

Я смотрел вокруг для решения, и мне было интересно, если это заявление было бы все, что мне нужно (вместе с соответствующим кодом в моем .cpp):

const uint8_t operator[](const std::size_t index) const; 

Хотя я абсолютно уверен, что это будет работать, я до сих пор какой-то о моем подходе, и я надеялся, что вы сможете помочь мне в моих проблемах.

  1. Действительно ли это «нормально», чтобы просто вернуть значение, а не ссылку? Я знаю, что во ВСЕХ примерах, которые я видел, возвращается ссылка. Возвращает ли значение значение, которое помогает мне обойти тот факт, что я не хочу, чтобы «[]» использовался в левой части операции? Опять же, разве const не предотвращает это?

  2. Будет ли функция const вызываться даже на неконстантном объекте? Я видел несколько примеров, когда есть версия const оператора и неконстантная объявленная оператором. Неконстант допускает запись, тогда как константа разрешает чтение, но вызывается только для объектов const. Моя цель состоит в том, чтобы иметь даже неконстантные объекты только возможность чтения.

  3. Есть ли чистый способ передать ошибки от оператора? Моя основная проблема заключается в том, что запрашиваемые данные могут быть за пределами данных, которые у меня есть. Все примеры, которые я видел, используют утверждение, но я не обязательно хочу, чтобы программа выпадала из строя в том случае, если вызов пользователя к оператору вызывает какой-то веселье. Я также не могу обязательно передавать специальный код, поскольку любое значение байта, которое я передаю, может быть действительным.

Как всегда, спасибо за вашу помощь, как я медленно (но верно) сделать страшный переход от того, чтобы быть C программисту мастера OO C++.

+1

У вас действительно есть требование, чтобы ваш код не компилировался в системе, где char больше 8 бит? Потому что это то, что делает 'uint8_t': он не существует, если у системы нет неподписанного типа с ** точно ** 8 бит. Разумеется, 'uint_least8_t' или' uint_fast8_t' более уместен. Или даже лучше, 'unsigned char', который всегда будет не менее 8 бит. –

+0

Я использую uint_8t, так как это предпочтительный метод в руководстве по стилю Google http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Integer_Types. Кроме того, класс пакета никогда не будет запущен в системе, где я не могу получить беззнаковый тип ровно 8 бит. –

+1

Руководство по стилю Google имеет репутацию часто ошибочного. Это, безусловно, здесь, поскольку он излишне делает код не переносным. –

ответ

7
  1. Да, это нормально, чтобы просто вернуть значение, для такого маленького типа, как uint8_t. Вы можете возвратить константную ссылку, и const действительно не позволит кому-либо писать через нее. Но с небольшими типами, такими как uint8_t, возвращение по значению - лучшая идея. Обратите внимание, BTW, что при возврате по значению вам больше не нужно const по типу возврата.

    Возвращаясь константную ссылку, даже трудно это предотвращает изменение, дает вызывающему коду возможность создавать и хранить потенциально долгоживущие ссылки и указатели на свои элементы массива, как в

    const uint8_t *byte = &packet[3]; 
    

    Если это нежелательно , а затем возврат значениями значений этой возможности.

  2. Да, const Вариант функции будет вызываться для объектов, не являющихся константами (если вы не предоставили неконстантную версию).

  3. Исключения были введены специально для этой цели. Исключения дают вам выделенный путь обратной связи для ошибочных ситуаций, не влияя на объявление функции и спецификацию (т. Е. Вам не нужно резервировать любые значения для ошибок и не нужно вводить какие-либо параметры для этой цели).

+0

Вау, почти дословно мой ответ. Я удаляю мои :-) – dhavenith

1

Если вернуться к значение и использовать

packet[3] = 0xAA; 

компилятор дает ошибку, так как пакет [3] не является изменяемым л-значение, которое означает, что она не может появиться на левой - сторона стороны задания.

Если вы возвращаетесь по ссылке, пользователь может редактировать все, на что ссылается. Вы можете использовать const ссылку на запрещение модификаций.

Исходный подход имеет то преимущество, что вы избегаете копии значения, которое может увеличить эффективность/пространство, если возвращаемое значение оператора [] велико. Если вам нужна только одна копия возвращаемого значения оператора [], вы должны использовать ссылку (const).

Смежные вопросы