Вопрос

Кто-то рассказал мне о разнице в стиле C ++ в их команде.У меня есть своя точка зрения на этот счет, но мне было бы интересно плюсы и минусы исходит от всех.

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

class T ;

class MethodA
{
   public :
      const T & get() const ;
      T & get() ;

      // etc.
} ;

class MethodB
{
   public :
      const T & getAsConst() const ;
      T & get() ;

      // etc.
} ;

Каковы были бы плюсы и минусы каждого метода?

Меня больше интересуют технические / семантические причины C ++, но стилевые соображения тоже приветствуются.

Обратите внимание , что MethodB имеет один серьезный технический недостаток (подсказка:в общем коде).

Это было полезно?

Решение

Ну, во-первых, getAsConst должен вызывается, когда указатель 'this' равен const, а не когда вы хотите получить объект const.Таким образом, наряду с любыми другими проблемами, это слегка неправильное название.(Вы все еще можете вызвать это, когда "это" не является постоянным, но это ни здесь, ни там.)

Игнорируя это, getAsConst ничего вам не приносит и возлагает неоправданную нагрузку на разработчика, использующего интерфейс.Вместо того чтобы просто вызывать "get" и знать, что он получает то, что ему нужно, теперь он должен выяснить, использует ли он в данный момент переменную const, и должен ли новый объект, который он захватывает, быть const .И позже, если оба объекта станут неконстантными из-за какого-то рефакторинга, он должен отключить свой вызов.

Другие советы

C ++ должен быть вполне способен справиться с методом A практически во всех ситуациях.Я всегда пользуюсь им, и у меня никогда не было проблем.

Метод В - это, на мой взгляд, случай нарушения OnceAndOnlyOnce.И теперь вам нужно выяснить, имеете ли вы дело со ссылкой const, чтобы написать код, который компилируется в первый раз.

Я предполагаю, что это стилистическая вещь - технически они оба работают, но methodA заставляет компилятор работать немного сложнее.Для меня это хорошая вещь.

Лично я предпочитаю первый метод, потому что он обеспечивает более согласованный интерфейс.Кроме того, для меня getAsConst() звучит примерно так же глупо, как getAsInt().

С другой стороны, вам действительно следует дважды подумать, прежде чем возвращать неконстантную ссылку или неконстантный указатель на элемент данных вашего класса.Это приглашение людям использовать внутреннюю работу вашего класса, которая в идеале должна быть скрыта.Другими словами, это нарушает инкапсуляцию.Я бы использовал get() const и set() и возвращал неконстантную ссылку только в том случае, если нет другого способа, или когда это действительно имеет смысл, например, предоставить доступ на чтение / запись к элементу массива или матрицы.

Учитывая прецедент стиля, установленный стандартной библиотекой (т.Е. begin() и begin() const, чтобы назвать только один пример), должно быть очевидно, что метод A является правильным выбором.Я сомневаюсь в здравомыслии человека, который выбирает метод Б.

Итак, первый стиль, как правило, предпочтительнее.

Однако мы довольно часто используем вариацию второго стиля в кодовой базе, над которой я сейчас работаю, потому что мы хотим провести большое различие между постоянным и неконстантным использованием.

В моем конкретном примере у нас есть getTessellation и getMutableTessellation.Это реализовано с помощью указателя копирования при записи.По соображениям производительности мы хотим, чтобы const-версия использовалась везде, где это возможно, поэтому мы сокращаем название и даем ему другое имя, чтобы люди случайно не создавали копию, когда они все равно не собирались писать.

Хотя, похоже, ваш вопрос касается только одного метода, я был бы рад внести свой вклад в стиль.Лично я, по соображениям стиля, предпочитаю первое.В большинстве IDE для вас появится сигнатура типа функций.

Я бы предпочел первое.В коде это выглядит лучше, когда две вещи, которые по сути делают одно и то же, выглядят одинаково.Кроме того, у вас редко бывает неконстантный объект, но вы хотите вызвать метод const , так что это не так уж и важно (и в худшем случае вам понадобится только const_cast<>).

Первый позволяет изменять тип переменной (независимо от того, является ли она const или нет) без дальнейшего изменения кода.Конечно, это означает, что разработчик не получает уведомления о том, что это могло измениться по сравнению с предполагаемым путем.Так что на самом деле важно, цените ли вы возможность быстрого рефакторинга или наличие дополнительной системы безопасности.

Второе - это что-то связанное с венгерской нотацией, которую я лично НЕ НАДО вот так я буду придерживаться Первый способ.

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

Поскольку вы скрываете названия классов, эта пища для размышлений о стиле может быть применима, а может и не применяться:

Имеет ли смысл указывать этим двум объектам, methodA и methodB, значение "get" или "getAsConst"?Не могли бы вы отправить "get" или "getAsConst" в качестве сообщений любому объекту?

То, как я это вижу, как отправитель сообщения / вызывающий метод, ты это тот, кто получает значение;итак, в ответ на это сообщение "получить" вы отправляете некоторое сообщение methodA / methodB, результатом которого является значение, которое вам нужно получить.

Пример:Если вызывающей стороной methodA является, скажем, служба в SOA, а methodA - репозиторий, то внутри get_A() службы вызовите methodA.find_A_by_criteria(...) .

Основной технологический недостаток methodB, который я видел, заключается в том, что при применении к нему универсального кода мы должны удваивать код для обработки как const, так и неконстантной версии.Например:

Допустим, T является упорядочиваемым объектом (т. е. мы можем сравнивать с объектами типа T с помощью operator <), и допустим, мы хотим найти максимальное значение между двумя методами (соответственно.два метода b).

Для methodA все, что нам нужно закодировать, это:

template <typename T>
T & getMax(T & p_oLeft, T & p_oRight)
{
   if(p_oLeft.get() > p_oRight.get())
   {
      return p_oLeft ;
   }
   else
   {
      return p_oRight ;
   }
}

Этот код будет работать как с постоянными объектами, так и с неконстантными объектами типа T:

// Ok
const MethodA oA_C0(), oA_C1() ;
const MethodA & oA_CResult = getMax(oA_C0, oA_C1) ;

// Ok again
MethodA oA_0(), oA_1() ;
MethodA & oA_Result = getMax(oA_0, oA_1) ;

Проблема возникает, когда мы хотим применить этот простой код к чему-либо, следуя соглашению methodB:

// NOT Ok
const MethodB oB_C0(), oB_C1() ;
const MethodB & oB_CResult = getMax(oB_C0, oB_C1) ; // Won't compile

// Ok
MethodA oB_0(), oB_1() ;
MethodA & oB_Result = getMax(oB_0, oB_1) ;

Чтобы методb работал как с const, так и с неконстантной версией, мы оба должны использовать уже определенный getMax, но добавить к нему следующую версию getMax:

template <typename T>
const T & getMax(const T & p_oLeft, const T & p_oRight)
{
   if(p_oLeft.getAsConst() > p_oRight.getAsConst())
   {
      return p_oLeft ;
   }
   else
   {
      return p_oRight ;
   }
}

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

Конечно, при достаточной паранойе вторая шаблонная функция должна была называться getMaxAsConst ...И, таким образом, проблема распространилась бы сама по себе по всему коду...

:-п

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top