Чтение онлайн

на главную - закладки

Жанры

Эффективное использование C++. 55 верных способов улучшить структуру и код ваших программ

Майерс Скотт

Шрифт:

Подведем итог: когда вы выбираете между возвратом ссылки и возвращением объекта, ваша задача заключается в том, чтобы все работало правильно. О том, как сделать этот выбор менее накладным, должен заботиться разработчик компилятора.

Что следует помнить

• Никогда не возвращайте указатель или ссылку на локальный объект, ссылку на объект, распределенный в «куче», либо указатель или ссылку на локальный статический объект, если есть шанс, что понадобится более, чем один экземпляр такого объекта. В правиле 4 приведен

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

Правило 22: Объявляйте данные-члены закрытыми

В этом правиле мы поговорим о том, почему данные-члены не должны быть открытыми (public). Затем мы убедимся, что все аргументы против открытых данных-членов касаются также защищенных (protected). Это приведет нас к выводу, что данные-члены должны быть закрытыми (private), и на этом мы поставим точку.

Итак, открытые данные-члены. Почему нет?

Начнем с синтаксической непротиворечивости (см. также правило 18). Если данные-члены не будут открытыми, то единственный способ для пользователей добраться до объекта – через функции-члены. Если весь открытый интерфейс будет состоять из функций, то пользователям не нужно будет ломать голову, пытаясь вспомнить, где нужно применять скобки, а где – нет, когда он захотят обратиться к члену класса. Они будут ставить скобки, поскольку ничего, кроме функций, не существует. Долой лишнюю головную боль.

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

class AccessLevels {

public:

...

int getReadOnly const { return readOnly;}

void setReadWrite(int value) { readWrite = value;}

int getReadWrite { return readWrite;}

void setWriteOnly(int value) { writeOnly = value;}

private:

int noAccess; // нет доступа к этому int

int readOnly; // доступ к этому int только для чтения

int readWrite; // доступ к этому int для чтения и записи

int writeOnly; // доступ к этому int только для записи

};

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

Все еще не убедил? Тогда самое время доставать тяжелую артиллерию: инкапсуляция! Если

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

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

class SpeedDataCollection {

...

public:

void addValue(int speed); // добавить новое значение

double averageSoFar const; // вернуть среднюю скорость

...

};

Теперь рассмотрим реализацию функции-члена averageSoFar. Можно, например, завести в классе член, который представляет среднее арифметическое значений скоростей, накопленных на данный момент. Тогда функция averageSoFar будет просто возвращать значение этого члена класса. Другой подход заключается в том, чтобы вычислять среднее значение скорости в функции averageSoFar при каждом вызове, для чего ей придется просмотреть все данные в коллекции.

Первый подход (хранение текущей средней скорости) увеличивает размер каждого объекта SpeedDataCollection, потому что необходимо выделить место для члена данных, хранящего текущее среднее, накопленный итог и количество элементов данных. При этом averageSoFar может быть реализована очень эффективно: это будет просто встроенная функция (см. правило 30), которая возвращает значение текущего среднего. В противоположность этому вычисление по запросу сделает данную функцию медленнее, но каждый объект SpeedDataCollection станет меньше.

Кто скажет – как лучше? На машинах с маленькой памятью (например, встроенных устройствах, установленных на дороге), и в приложениях, где среднее значение требуется нечасто, его вычисление при каждом вызове, возможно, представляет лучшее решение. Но в приложениях, где среднее значение будет запрашиваться часто, скорость реакции существенна, а память – не проблема, хранение текущего среднего обычно предпочтительнее. Важно отметить, что, имея доступ к среднему через функцию-член (то есть инкапсулировав его), вы можете легко заменять реализацию, при этом программу-клиент придется всего лишь перекомпилировать. Можно избежать даже этого неудобства, если следовать технике, описанной в правиле 31.

Сокрытие данных-членов за интерфейсом функций может обеспечить гибкость реализации в разных отношениях. Например, это облегчает извещение других объектов о том, что к члену данных происходит обращение для чтения или записи, обеспечивает возможность проверять инварианты и выполнение пред– и постусловий, позволяет реализовать синхронизацию в многопоточной среде и т. д. Программисты, которые пришли в C++ из таких языков, как Delphi и C#, увидят в этой возможности аналогию со «свойствами» («properties»), существующими в этих языках, правда, к имени «свойства» приходится добавлять скобки.

Поделиться:
Популярные книги

Дракон - не подарок

Суббота Светлана
2. Королевская академия Драко
Фантастика:
фэнтези
6.74
рейтинг книги
Дракон - не подарок

Бастард Императора. Том 8

Орлов Андрей Юрьевич
8. Бастард Императора
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 8

Чужая дочь

Зика Натаэль
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Чужая дочь

Эра Мангуста. Том 2

Третьяков Андрей
2. Рос: Мангуст
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Эра Мангуста. Том 2

Идеальный мир для Лекаря 14

Сапфир Олег
14. Лекарь
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 14

Один на миллион. Трилогия

Земляной Андрей Борисович
Один на миллион
Фантастика:
боевая фантастика
8.95
рейтинг книги
Один на миллион. Трилогия

Помещицы из будущего

Порохня Анна
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Помещицы из будущего

Шлейф сандала

Лерн Анна
Фантастика:
фэнтези
6.00
рейтинг книги
Шлейф сандала

Черный маг императора 2

Герда Александр
2. Черный маг императора
Фантастика:
юмористическая фантастика
попаданцы
аниме
6.00
рейтинг книги
Черный маг императора 2

Император

Рави Ивар
7. Прометей
Фантастика:
фэнтези
7.11
рейтинг книги
Император

Бандит 2

Щепетнов Евгений Владимирович
2. Петр Синельников
Фантастика:
боевая фантастика
5.73
рейтинг книги
Бандит 2

На границе империй. Том 9. Часть 2

INDIGO
15. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 9. Часть 2

Князь Серединного мира

Земляной Андрей Борисович
4. Страж
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Князь Серединного мира

Чайлдфри

Тоцка Тала
Любовные романы:
современные любовные романы
6.51
рейтинг книги
Чайлдфри