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

1 ... 42 43 44 [ 45 ] 46 47 48 ... 96


Приемы Контекст создания объектов

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

class ColorPrinter: public Printer { };

Предположим теперь, что в системе есть один простой принтер и один цветной:

Printer р; ColorPrinter ср;

Сколько объектов Printer получится в результате этих определений объектов? Два: один для р и один для части Printer в ср. Во время работы программы при создании части базового класса в ср будет сгенерировано исключение TooManyObj ects. Для большинства программистов это будет и нежелательным, и неожиданным. (Если при разработке не использовать наследование конкретных классов от других конкретных классов, эта проблема не возникает. Детали такого подхода см. в правиле 33.)

Похожие сложности возникают, если объекты Printer находятся внутри других объектов:

class CPFMachine { Устройства, которые могут

копировать,

private: печатать и отправлять факсы.

Printer р; Принтер.

FaxMachine f; Факс.

CopyMachine с; Допировальный аппарат.

CPFMachine ml; Нормально.

CPFMachine m2; Генерирует исключение

TooManyObjects.

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

Часто вы заинтересованы в том, чтобы разрешить создание только отдельных объектов, и вам нужно ограничить число только таких экземпляров объекта. Этого легко добиться, используя исходную стратегию для класса Printer, поскольку конструкторы класса Printer при этом являются закрытыми, а классы с закрытыми конструкторами не могут быть использованы в качестве базовых классов (при отсутствии объявлений friend) и не могут быть встроены в другие объекты.



Запрет на создание производных классов от классов с закрытыми конструкторами приводит к общей схеме предотвращения создания производных классов, которая не обязательно должна сочетаться с ограничением числа экземпляров объекта. Предположим, например, что существует класс FSA для представления конечных автоматов. (Такие машины состояний полезны во многих случаях, включая разработку пользовательского интерфейса.) Предположим далее, вы хотите, чтобы можно было создать любое число объектов FSA, но в то же время иметь гарантию, что ни один класс не сможет наследовать от класса FSA. (Это может потребоваться, например, для того чтобы обеспечить существование невиртуального деструктора в классе FSA. Как объясняется в правиле 24, классы без виртуальных функций дают объекты меньшего размера, чем эквивалентные классы с виртуальными функциями.) Удовлетворить обоим критериям можно, реализовав класс FSA следующим образом:

class FSA { public:

Псевдоконструкторы.

static FSA * makeFSAO ;

static FSA * makeFSA(const FSA& rhs) ;

private: FSA () ;

FSA(const FSA& rhs);

FSA * FSA: :makeFSAO

{ return new FSA(); }

FSA * FSA: : makeFSA (const FSA& rhs)

{ return new FSA(rhs) ; }

В отличие о функции thePrinter, которая всегда возвращала ссылку на единственный объект, каждый псевдоконструктор makeFSA возвращает указатель на уникальный объект. Это позволяет создавать неограниченное число объектов FSA.

Однако вызов в каждом псевдоконструкторе оператора new подразумевает, что необходимо не забыть затем вызвать оператор delete, иначе возникнет утечка ресурсов. Для автоматического вызова delete при выходе из зоны видимости можно сохранять указатель, возвращаемый функцией makeFSA в объекте auto ptr (см. правило 9); такие объекты автоматически удаляют то, на что они ссылаются, когда покидают зону видимости:

Косвенный вызов конструктора по умолчанию FSA. auto ptr<FSA> pfsal(FSA::makeFSA()); Косвенный вызов конструктора копирования FSA. auto ptr<FSA> pfsa2(FSA::makeFSA(*pfsal));

... Используйте pfsal и pfsa2 как обычные указатели,

но не беспокойтесь об их удалении.



Разрешение создания и удаления объектов

Теперь вы знаете, как сформировать класс, разрешающий создание только одного экземпляра объекта. Кроме того, вам известно: отслеживание числа объектов определенного класса осложняется тем, что конструкторы объекта вызываются в трех различных контекстах, и чтобы избавиться от этой путаницы, надо сделать конструкторы закрытыми. И еще одно, последнее замечание. Применение функции thePrinter для инкапсуляции доступа к единственному объекту сводит число объектов Printer к одному, но во время каждого запуска программы может быть всего один объект Printer. В результате нельзя написать такой код:

создать объект р1 типа Printer; использовать р1; уничтожить р1;

создать объект р2 типа Printer; использовать р2; уничтожить р2;

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

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

class Printer { public:

class TooManyObjects{};

Псевдоконструктор.

static Printer * makePrinter();

-Printer{);

void submitJob(const PrintJob& job) ;

void reset();

void performSelfTest();

private:

static size t numObjects; Printer{);

Printer(const Printers rhs); Эта функция

}; не определяется, так как

копирование не разрешено. Обязательное определение статического объекта класса. size t Printer::numObjects = 0; Printer::Printer() {

if (numObjects >= 1) {

throw TooManyObjects();



1 ... 42 43 44 [ 45 ] 46 47 48 ... 96

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