Немного более подробный, чем Мейерс, но я могу сделать следующее:
class X {
private:
// This method MUST NOT be called except from boilerplate accessors.
Z &_getZ(size_t index) const {
return something;
}
// boilerplate accessors
public:
Z &getZ(size_t index) { return _getZ(index); }
const Z &getZ(size_t index) const { return _getZ(index); }
};
У частного метода есть нежелательное свойство, заключающееся в том, что он возвращает неконстантный Z & для константного экземпляра, поэтому он частный. Частные методы могут нарушать инварианты внешнего интерфейса (в этом случае желаемый инвариант - это «константный объект не может быть изменен через полученные через него ссылки на объекты, которые он имеет-a»).
Обратите внимание, что комментарии являются частью шаблона - интерфейс _getZ указывает, что его нельзя вызывать (кроме средств доступа, очевидно): в любом случае нет никакой мыслимой выгоды от этого, потому что это еще 1 символ для ввода и не будет приводит к меньшему или более быстрому коду. Вызов метода эквивалентен вызову одного из методов доступа с const_cast, и вы бы тоже не захотели этого делать. Если вы беспокоитесь о том, чтобы ошибки были очевидными (и это справедливая цель), назовите его const_cast_getZ вместо _getZ.
Кстати, я ценю решение Мейерса. У меня нет никаких философских возражений против этого. Лично я предпочитаю немного контролируемого повторения и частный метод, который должен вызываться только в определенных строго контролируемых обстоятельствах, а не методу, который выглядит как линейный шум. Выберите свой яд и придерживайтесь его.
[Изменить: Кевин правильно указал, что _getZ может захотеть вызвать другой метод (скажем, generateZ), который специализируется на константе так же, как и getZ. В этом случае _getZ увидит const Z & и должен будет преобразовать его в const_cast перед возвратом. Это по-прежнему безопасно, поскольку шаблонный аксессуар контролирует все, но не совсем очевидно, что это безопасно. Кроме того, если вы сделаете это, а затем измените generateZ, чтобы он всегда возвращал const, вам также нужно изменить getZ, чтобы всегда возвращать const, но компилятор не скажет вам, что вы это делаете.
Последний пункт о компиляторе также верен для рекомендованного Мейерса шаблона, но первый пункт о неочевидном const_cast - нет. Итак, в целом, я думаю, что если _getZ окажется, что для его возвращаемого значения требуется const_cast, то этот шаблон теряет большую часть своего значения по сравнению с шаблоном Мейерса. Поскольку он также имеет недостатки по сравнению с устройством Мейерса, я думаю, что в этой ситуации я бы переключился на его. Выполнить рефакторинг с одного кода на другой просто - он не влияет ни на какой другой допустимый код в классе, поскольку только недопустимый код и шаблон вызывает _getZ.]
person
Steve Jessop
schedule
23.09.2008