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

на главную

Жанры

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

Майерс Скотт

Шрифт:

typedef std::vector<std::tr1::shared_ptr<Window>>VPW;

VPW winPtrs; // контейнер содержит

// (указатели на) все возможные

... // типы окон

for(VPW::iterator iter = winPtrs.begin;

iter != winPtrs.end;

++iter) // dynamic_cast не используется

(*iter)->blink;

Ни один из этих подходов – с применением безопасных по отношению к

типам контейнеров или перемещением виртуальной функции вверх по иерархии – не является универсально применимым, но во многих случаях они представляют полезную альтернативу dynamic_cast. Пользуйтесь ими, когда возможно.

Но вот чего стоит избегать всегда – это каскадов из операторов dynamic_cast, то есть чего-то вроде такого кода:

class Window {...};

... // здесь определены производные классы

typedef std::vector<std::tr1::shared_ptr<Window>> VPW;

VPW winPtrs;

...

for (VPW::iterator iter = winPtrs.begin; iter != winPtrs.end; ++iter)

{

if (SpecialWindow1 *psw1=

dynamic_cast<SpecialWindow1>(iter->get)) {...}

else if (SpecialWindow2 *psw2=

dynamic_cast<SpecialWindow2>(iter->get)) {...}

else if (SpecialWindow2 *psw2=

dynamic_cast<SpecialWindow2>(iter->get)) {...}

...

}

В этом случае генерируется объемный и медленный код, к тому же он нестабилен, потому что при каждом изменении иерархии классов Window весь этот код нужно пересмотреть на предмет обновления. Например, если добавится новый производный класс, то вероятно, придется добавить еще одну ветвь в предложение if. Подобный код почти всегда должен быть заменен чем-то на основе вызова виртуальных функций.

В хорошей программе на C++ приведения типов используются очень редко, но полностью отказываться от них тоже не стоит. Так, показанное выше приведение int к double является разумным, хотя и не абсолютно необходимым (код может быть переписан с объявлением новой переменной типа double, инициируемой значением x). Как и большинство сомнительных конструкций, приведения типов должны быть изолированы насколько возможно. Обычно они помещаются внутрь функций, чей интерфейс скрывает от пользователей те некрасивые дела, что творятся внутри.

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

• Избегайте насколько возможно приведений типов, особенно dynamic_cast, в критичном по производительности коде. Если дизайн требует приведения, попытайтесь разработать альтернативу, где такой необходимости не возникает.

• Когда приведение типа необходимо, постарайтесь скрыть его внутри функции. Тогда пользователи смогут вызывать эту функцию вместо помещения приведения в их собственный код.

• Предпочитайте приведения в стиле C++ старому стилю. Их легче увидеть, и они более избирательны.

Правило 28: Избегайте возвращения «дескрипторов» внутренних данных

Представим, что вы работаете над приложением,

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

class Point { // класс, представляющий точки

public:

Point(int x, int y);

...

void setX(int newVal);

void setY(int newVal);

...

};

struct RectData { // точки, определяющие Rectangle

Point ulhc; // ulhc – верхний левый угол

Point lrhc; // lrhc – нижний правый угол

};

class Rectangle {

...

private:

std::tr1::shared_ptr<RectData> pData; // см. в правиле 13

}; // информацию о tr1::shared_ptr

Поскольку пользователям класса Rectangle понадобится определять его координаты, то класс предоставляет функции upperLeft и lowerRight. Однако Point – это определенный пользователем тип, поэтому, помня о том, что передача таких типов по ссылке обычно более эффективна, чем передача по значению (см. правило 20), эти функции возвращают ссылки на внутренние объекты Point:

class Rectangle {

public:

...

Point& upperLeft const { return pData->ulhc;}

Point& lowerRight const { return pData->lrhc;}

...

};

Такой вариант откомпилируется, но он неправильный! Фактически он внутренне противоречив. С одной стороны, upperLeft и lowerRight объявлены как константные функции-члены, поскольку они предназначены только для того, чтобы предоставить клиенту способ получить информацию о точках Rectangle, не давая ему возможности модифицировать объект Rectangle (см. правило 3). С другой стороны, обе функции возвращают ссылки на закрытые внутренние данные – ссылки, которые пользователь может затем использовать для модификации этих внутренних данных! Например:

Point coord1(0, 0);

Point coord2(100,100);

const Rectangle rec(coord1, coord2); // rec – константный прямоугольник

// от (0, 0) до (100, 100)

rec.upperLeft.setX(50); // теперь rec лежит между

// (50, 0) и (100, 100)!

Обратите внимание, что пользователь функции upperLeft может использовать возвращенную ссылку на один из данных-членов внутреннего объекта Point для модификации этого члена. Но ведь ожидается, что rec – константа!

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

Возвышение Меркурия. Книга 12

Кронос Александр
12. Меркурий
Фантастика:
героическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 12

Кодекс Охотника. Книга XXIV

Винокуров Юрий
24. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга XXIV

Буря империи

Сай Ярослав
6. Медорфенов
Фантастика:
аниме
фэнтези
фантастика: прочее
эпическая фантастика
5.00
рейтинг книги
Буря империи

Месть за измену

Кофф Натализа
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Месть за измену

Деспот

Шагаева Наталья
Любовные романы:
современные любовные романы
эро литература
5.00
рейтинг книги
Деспот

Осознание. Пятый пояс

Игнатов Михаил Павлович
14. Путь
Фантастика:
героическая фантастика
5.00
рейтинг книги
Осознание. Пятый пояс

Тринадцатый VII

NikL
7. Видящий смерть
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Тринадцатый VII

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

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

Ветер перемен

Ланцов Михаил Алексеевич
5. Сын Петра
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Ветер перемен

Приручитель женщин-монстров. Том 11

Дорничев Дмитрий
11. Покемоны? Какие покемоны?
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Приручитель женщин-монстров. Том 11

На границе империй. Том 7

INDIGO
7. Фортуна дама переменчивая
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
6.75
рейтинг книги
На границе империй. Том 7

Прометей: владыка моря

Рави Ивар
5. Прометей
Фантастика:
фэнтези
5.97
рейтинг книги
Прометей: владыка моря

Бракованная невеста. Академия драконов

Милославская Анастасия
Фантастика:
фэнтези
сказочная фантастика
5.00
рейтинг книги
Бракованная невеста. Академия драконов

Кодекс Охотника. Книга XXII

Винокуров Юрий
22. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Кодекс Охотника. Книга XXII