Вызов this-> get / this-> set методов по сравнению с прямым доступом к переменным-членам в C ++ - PullRequest
5 голосов
/ 03 марта 2010

Предположим, у меня есть класс Foo с закрытой переменной bar_, содержащей состояние для Foo. При необходимости я могу написать публичные методы get / set для bar_. Естественно, я максимально избегаю этого, чтобы поддерживать инкапсуляцию.

Предполагая, что у меня есть эти методы get / set, всякий раз, когда мне нужно получить доступ или изменить bar_ в методе, принадлежащем к Foo, я обычно делаю это прямо к bar_ вместо использования методов get / set который я использую для доступа к bar_ извне класса. У меня нет никакого оправдания, кроме опасений, касающихся скорости прямого доступа к переменной и вызова методов, но я подозреваю, что если методы get / set определены inline (каковы они есть), это не должно иметь значения. Есть ли разница? const играет ли в этом роль?

Пока у меня не было никаких проблем с этим, но у меня осталось ощущение, что я делаю это неправильно. Есть ли веские аргументы для того, чтобы этого не делать? Есть ли какие-либо рекомендации по этому поводу?

Ответы [ 7 ]

14 голосов
/ 03 марта 2010

Я знаю, что это близко к отсюда, но я ненавижу методы get / set. Ненависть им. Почти никогда их не пиши.

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

Даже если бы я написал один, я бы почти никогда не использовал его внутри класса. Весь смысл в том, что вы можете изменить внутреннее представление вещей, не влияя на клиента. Внутри класса это ваше внутреннее представление! Если вы испытываете желание сделать много операций над классом, используя собственный интерфейс внутри класса, у вас, вероятно, есть второй класс, пытающийся выйти из него.

5 голосов
/ 03 марта 2010

У меня нет никаких оснований, кроме вопросов, касающихся скорости прямого доступа к переменной и вызова методов, но я подозреваю, что если методы get / set определены inline (каковы они есть), это не должно иметь значения. Есть ли разница? Константность играет в этом роль?

Ключевое слово inline вряд ли играет роль в том, выполняет ли компилятор какие-либо вставки. Использование ключевого слова в этом отношении по существу не рекомендуется. Современные компиляторы встроены как сумасшедшие, и они знают, когда делать это лучше, чем любой программист.

Любой грязный компилятор скажет: «Хм, вызови эту функцию, чтобы получить эту переменную-член; эй, я могу просто получить переменную-член!» Вы ни о чем не беспокоитесь. Это происходит независимо от встроенных ключевых слов.

Тем не менее, я почти всегда использую функции-члены. Если я изменяю поведение переменной при обращении к ней, я теперь «автоматически» применяю ее везде, где она используется. Чистый код должен быть вашей целью, а не догматическим «всегда пропускать функции» или нет.

В любое время, когда я просто хочу значение переменной, я использую соответствующую переменную-член. (то есть, если бы я писал std::vector, если бы мне нужно было проверить, был ли размер меньше чем-то, я бы сказал size() < x). Но если лучше использовать переменную напрямую, сделайте это, например, mSize++.

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

2 голосов
/ 03 марта 2010

Лучше использовать методы get и set: он чище, лучше поддерживает принципы DRY (выполняет проверку только один раз) и позволяет подклассам переопределять методы и видеть согласованное поведение при всех изменениях переменной. 1003 *

1 голос
/ 03 марта 2010

get / set должно быть необходимо только тогда, когда есть какой-то инвариант, предусловие или постусловие, которые должны поддерживаться классом. Если изменение значения не имеет «волнового эффекта» в остальной части класса, то пользователь должен иметь возможность изменить его напрямую. Однако, если изменение значения вызовет что-то еще (например, изменение размера кэша может привести к очистке кэшированных элементов), тогда get / set подходит.

1 голос
/ 03 марта 2010

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

Есть оправдания для использования функций get / set для внутренних целей в больших классах, особенно когда bar_ является чем-то, что не является ключевым элементом дизайна реализации класса и, возможно, может быть изменено без существенного влияния на остальную его часть. Однако во многих случаях, если вы изменяете внутреннее представление таким образом, что bar_ больше не существует и его соответствующее get_bar() вычисляется, вы почти наверняка захотите пересмотреть внутреннее использование, чтобы определить, хотите ли вы его реорганизовать. так что он не делает этого вычисления или делает это иначе.

С учетом вышесказанного, скорость не является оправданием для того, чтобы этого не делать - но стоимость понимания слишком большого количества уровней инкапсуляции равна ; класс из сорока строк не должен быть сложным с дополнительной внутренней инкапсуляцией, если только это не один из случаев, когда инкапсуляция фактически упрощает код.

Редактировать: Кроме того, ehdv поднимает важную проблему, которую я пропустил: если вы ожидаете, что производные классы переопределяют этот фрагмент внутреннего представления, использование функций get / set может упростить последовательное переопределение. Так что это может быть еще одним фактором в решении.

0 голосов
/ 03 марта 2010

На мой взгляд, нет правил, подходящих для любой ситуации. Иногда лучше написать эти частные функции set / get, иногда это не так.

Например, если все, что делают функции get / set, это:

void set(int n)
{
   member_n = n;
}
int get_n() const
{
  return member_n;
}

Тогда на самом деле эти функции не нужны!

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

void setAngle(int angle)
{
  member_angle = angle%two_PI;
}
0 голосов
/ 03 марта 2010

Если ваш компилятор вообще делает какие-либо вставки, он сможет встроить методы get и set, определенные и используемые в данном классе. const не имеет к этому никакого отношения, и директива inline также не имеет большого значения.

Обычно я предпочитаю использовать мои get() и set() методы даже из определения класса, когда могу. Вы получаете все те же преимущества, что и вы, используя их вне определения класса, и штраф за скорость не взимается.

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