Я читаю книгу под названием "Стандарт кодирования на C++". Херб Саттер, Андрей Александреску и в главе 42 этой книги - пример: (глава короткая, поэтому я беру на себя смелость и вставляю ее часть)
Рассмотрим:
class Socket {
public:
// … constructor that opens handle_, destructor that closes handle_, etc. …
int GetHandle() const {return handle_;} // avoid this - (1) <-why this is bad code?
// and why there is a comment to avoid such code??
private:
int handle_; // perhaps an OS resource handle
};
Скрытие данных - это мощное устройство абстракции и модульности (см. пункты 11 и 41). Но прятать данные, а затем раздавать ручки к нему самопровозглашает себя, точно так же, как запирать ваш дом и оставлять ключи в замке. Это происходит потому, что:
У клиентов теперь есть два способа реализовать функциональность: они могут использовать абстракцию вашего класса (Socket) или напрямую манипулировать реализацией, на которую опирается ваш класс (дескриптор C-стиля сокета). В последнем случае объект не знает о значительных изменениях в ресурсе, который, по его мнению, принадлежит ему. Теперь класс не может надежно обогащать или приукрашивать функциональность (например, проксирование, протоколирование, сбор статистики), поскольку клиенты могут обойти украшенную контролируемую реализацию и любые инварианты, которые он считает добавлением, что делает правильную обработку ошибок практически невозможной (см. Пункт 70).
Класс не может изменить базовую реализацию своей абстракции, потому что клиенты зависят от него: если Socket позже будет обновлен, чтобы поддерживать другой протокол с другим набором примитивов низкого уровня, вызывая код, который извлекает базовый дескриптор_ и неправильно обрабатывает его будет тихо нарушена.
Класс не может принудительно применять свои инварианты, потому что вызывающий код может изменять состояние без ведома класса: например, кто-то может закрыть дескриптор, используемый объектом Socket, не проходя через функцию-член Socket, тем самым делая объект недействительным.
Клиентский код может хранить дескрипторы, возвращаемые вашим классом, и попытаться использовать их после того, как ваш код класса сделал их недействительными.
это резюме из этой книги:
Не пользуйтесь слишком много: избегайте возврата дескрипторов во внутренние данные, управляемые вашим классом, поэтому клиенты не будут неуправляемо изменять состояние, которое ваш объект считает собственником.
В основном я прошу:
-
Почему строка, отмеченная мной как (1), указана в качестве примера плохого кода (я всегда думал, что возвращающие указатели или ссылка - плохая идея, но возврат по значению - это нормально. Здесь они говорят, что возвращение по значению - плохая идея тоже?)
-
Возможно ли, что есть & отсутствует и что они на самом деле означают - не возвращать внутренние данные по ссылке или указателям?
Спасибо.