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

1 ... 44 45 46 [ 47 ] 48 49 50 ... 96


template<class BeingCounted> void Counted<BeingCounted>::init() {

if (numObjects >= maxObjects) throw TooManyObj ects () , ++numObjects;

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

Теперь можно изменить класс Printer, используя шаблон Counted:

class Printer: private Counted<Printer> { public:

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

static Printer * makePrinter{);

static Printer * makePrinter(const Printers rhs); -Printer();

void submitJob(const PrintJob& job);

void reset();

void performSelfTest();

using Counted<Printer>: :objectCount; См. ниже,

using Counted<Printer>::TooManyObjects; См. ниже,

private:

Printer 0;

Printer(const Printers rhs);

To, что класс Printer отслеживает число сзтцествующих объектов Printer с помощью шаблона Counted, честно говоря, не касается никого, кроме автора класса Printer. Такие детали реализации лучше всего делать закрытыми, и поэтому здесь применяется закрытое наследование. Альтернативный метод - использовать открытое наследование между Printer и Counted<Printer>, но в этом случае вы были бы вынуждены определить в классах Counted виртуальный деструктор. (Иначе возник бы риск неправильного поведения, если кто-либо удалил бы объект Printer при помощи указателя Counted<Printer>*.) Как поясняется в правиле 24, наличие виртуальной функции в классе Counted практически всегда будет влиять на размер и состав объектов классов, наследующих от Counted. Дополнительные расходы вам не нужны, и использование закрытого наследования позволяет избежать этого.

Совершенно правильно, что большая часть действий класса Counted скрыта от клиентов объекта Printer, но клиенты должны иметь способ определять число существующих объектов Printer. Шаблон Counted включает функцию obj ectCount, которая выдает эту информацию, однако данная функция в объекте



для клиентов Printer.

Это вполне допустимо, но только если ваши компиляторы поддерживают пространства имен. В противном cnjae вы можете использовать старый синтаксис объявления доступа:

class Printer: private Counted<Printer> { public:

Counted<Printer>::objectCount; Сделать objectCount

открытой в объекте

Printer.

Этот более традиционный синтаксис означает то же самое, что и объявление using, но он обладает определенными недостатками. Класс TooManyObj ects обрабатывается аналогично классу ObjectCount, так как клиенты объекта Printer должны иметь доступ к TooManyObjects, если они могут перехватывать исключения данного типа.

Если класс Printer наследует от класса Counted<Printer>, он может забыть о подсчете объектов. Иногда этот класс пишется так, как будто действия по подсчету выполняются где-то еще, а именно в классе (Counted<Printer>). Конструктор Printer в таком сл5ае выглядит следующим образом:

Printer::Printer{) {

продолжить обычное создание объекта;

Здесь интересно не то, что вы видите, а то, чего вы не видите. Здесь нет проверки числа объектов, счетчик объектов не увеличивается после завершения конструктора. Все эти операции выполняются конструкторами Counted<Printer>, и так как Counted<Printer> является базовым классом для класса Printer, то вы знаете, что перед конструктором Printer будет всегда вызываться конструктор Counted<Printer>. Если создается слишком много объектов, то конструктор Counted<Printer> сгенерирует исключение, и конструктор Printer не будет вызываться вообще. Остроумно, не так ли?

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

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

class Printer: private Counted<Printer> { public:

using Counted<Printer>::objectCount; Сделать эту

функцию открытой



объектов внутри класса Counted. Можно достаточно просто обойтись с переменной NumObjects, поместив в файл Counted следующий код:

template<class BeingCounted> Определяет переменную

int Counted<BeingCounted>::numObjects; numObjects

и автоматически

инициализирует ее нулем.

Ситуация с переменной MaxObj ects немного сложнее. Какое начальное значение вы должны присвоить этой переменной? Если вы хотите разрешить создание не более 10 принтеров, следует проинициализировать Counted<Prin-ter>: :maxObjects значением 10. С другой стороны, если вы допускаете существование не более 16 файловых дескрипторов, то надо проинициализировать Counted<FileDescriptor>: :maxObjects значением 16. Что же делать?

Выбирайте самый простой путь: не делайте ничего. Не инициализируйте переменные maxObj ects. Вместо этого требуйте, чтобы соответствующую инициализацию выполняли клиенты данного класса. Автор класса Printer должен добавить в файл реализации следующее:

const size t Counted<Printer>::maxObjects = 10;

Аналогично, автору класса FileDescriptor необходимо добавить строку:

const size t Counted<FileDescriptor>::maxObjects = 16;

Что произойдет, если авторы этих классов забудут определить переменную maxObjects? Они просто получат сообщение об ошибке во время компоновки, так как переменная maxObjects останется неопределенной. Если вы описали данное требование для пользователей класса Counted, они вспомнят об этом и добавят необходимую инициализацию.

Правило 27. В зависимости от ситуации требуйте или запрещайте размещать объекты в куче

Иногда необходимо организовать работу так, чтобы объекты определенного типа могли самоуничтожаться, то есть выполнять оператор delete this. Очевидно, что при этом объекты должны быть динамическими. Иногда же нужно быть уверенными, что для определенного класса не возникнут утечки памяти, так как все его объекты расположены не в куче. Это может потребоваться при разработке системы для промышленных применений, когда утечки памяти особенно опасны, а размер кучи ограничен. Можно ли создать код, гарантирующий или запрещающий размещение объектов в куче? Во многих случаях да, но имейте в виду, что понятие объект находится в куче часто трактуется по-разному.

Гарантированное размещение объектов в куче

Рассмотрим вначале запрет на создание объектов вне кучи. Чтобы ввести такое ограничение, вы должны найти способ запретить клиентам создание объектов любым способом, кроме вызова оператора new. Сделать это легко. Объекты, не



1 ... 44 45 46 [ 47 ] 48 49 50 ... 96

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