Программирование >>  Оптимизация возвращаемого значения 

1 ... 38 39 40 [ 41 ] 42 43 44 ... 96


Глава 5. Приемы

Большая часть книги посвяшена принципам программирования. Они, конечно, важны, но программисты не живут только принципами. Как говорилось в старом мультсериале Кот Феликс : Попадая впросак, достает он трюков рюкзак . Если персонаж мультфильма может иметь рюкзак трюков, это могут и программисты на С++. Считайте эту главу началом вашей коллекции нестандартных приемов.

При разработке программ на языке С++ специалисты постоянно сталкиваются с одними и теми же проблемами. Как заставить конструкторы и функции, не являющиеся членами класса, работать подобно виртуальным функциям? Как предотвратить создание объектов в Kjie? Как, наоборот, гарантировать их создание там? Как создавать объекты, которые автоматически выполняют какие-либо функции при вызове других функций - членов класса? Как разные объекты могут совместно использовать структуры данных, чтобы у клиентов при этом возникала иллюзия, будто каждый из объектов обладает собственной копией? Как различать выполнение записи и чтения в operator [ ] ? Как создать виртуальную функцию, поведение которой зависит от динамического типа нескольких объектов?

В настоящей главе, где описаны проверенные решения для задач, часто возникающих перед программистами на С++, даются ответы на все эти (и многие другие) вопросы. Я называю такие решения приемами, но они также известны как идиомы или, если изложены стилизованно, прототипы. Независимо от того, как вы будете их называть, изложенная ниже информацию обязательно пригодится вам в ежедневной практической работе. Эта глава должна также убедить вас, что для языка С++ практически нет ничего невозможного.

Правило 25. Делайте виртуальными конструкторы и функции, не являющиеся членами класса

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

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



состоят из блоков текста или графики. Можно организовать программу следующим образом:

class NLComponent { public:

Абстрактный базовый класс для блоков сообщения.

class TextBlock: public NLComponent { public:

He содержит }; абстрактных функций.

class Graphic: public NLComponent { public:

He содержит }; абстрактных функций.

class NewsLetter { Объект сообщения,

public: Состоит из списка

объектов NLComponent.

private:

list<NLComponent*> components;

Классы связаны так, как показано на рис. 5.1.


( класс \

I TextBlock ]

класс

Graphic

Рис. 5.

Класс list, используемый внутри объекта NewsLetter, является частью стандартной библиотеки шаблонов, которая входит в стандартную библиотеку языка С++ (см. правило 35). Объекты типа list ведут себя как двусвязные списки, хотя они и не обязательно должны быть реализованы именно так.

Объекты NewsLetter, к которым еще не обращались, вероятно, находятся на диске. Чтобы формировать объект NewsLetter из его образа на диске, было бы удобно создать для него конструктор с параметром istream. Этот конструктор



* Строго говоря, эта функция не является конструктором, но поскольку виртуальные конструкторы в С++ в отличие от Object Pascal или SmallTalk отсутствуют, использование данного термина применительно к такого рода функциям не должно вызывать затруднений у читателя. (Прим. ред.)

станет считывать информацию из потока после создания необходимых внутренних структур данных:

class NewsLetter { public:

NewsLetter (istreamSt str) , };

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

NewsLetter::NewsLetter(istream& str) {

while (str) {

считать следующий объект из потока str; добавить объект к списку блоков сообщения;

ИЛИ, если поместить код для чтения из потока в отдельную функцию readComponent, так: class NewsLetter { public:

private:

Считать данные следующего блока NLComponent из str, создать блок и вернуть указатель на него, static NLComponent * readComponent{istream& str) ;

NewsLetter::NewsLetter(istream& str) {

while (str) {

Добавить указатель, который вернула функция readComponent в конец списка блоков; push back - это функция - член списка, вставляющая элемент в конец списка.

components.push bacl<(readComponent{str));

Рассмотрим работу функции readComponent. Она создает новый объект, имеющий тип TextBlock или Graphic в зависимости от считываемых данных. Так как она создает новые объекты, то работает почти как конструктор, но поскольку при этом могут создаваться объекты разных типов, ее обычно называют виртуальным конструктором. Виртуальный конструктор - это функция, которая создает объекты разного типа в зависимости от входных данных*. Виртуальные



1 ... 38 39 40 [ 41 ] 42 43 44 ... 96

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика