Программирование >>  Разработка устойчивых систем 

1 ... 159 160 161 [ 162 ] 163 164 165 ... 196


та будет интерпретирован как относящийся к типу Shape, а не к типу, производному от Shape. Только при перенаправлении вызова через s заработает механизм виртуального вызова. Пример показывает, что в функции mainQ все работает правильно, даже при вызове функций в конструкторах и деструкторах.

Работа деструкторов

Уничтожение объектов в этой схеме тоже происходит нетривиально. Чтобы разобраться, давайте мысленно проследим за тем, что происходит при вызове оператора delete для указателя на объект Shape (а конкретно Square), созданный в куче (ситуация с объектом, созданным в стеке, проще). Вызов delete через полиморфный интерфейс осуществляется при вызове purge().

В shapes хранятся указатели на базовый класс Shape, поэтому компилятор направляет вызов через Shape. В обычной ситуации такой вызов был бы виртуальным, что привело бы к вызову деструктора Square. Но в имитации виртуального конструктора компилятор создает объекты общего типа Shape, хотя конструктор инициализирует указатель конкретным подтипом Shape. Механизм виртуального вызова используется, но VPTR в объекте Shape указывает на таблицу виртуальных функций Shape, а не Square. В результате будет вызван деструктор Shape, который вызывает delete для указателя s в письме , фактически ссылающегося на объект Square. Вызов также является виртуальным, ио на этот раз он разрешается в деструктор Square.

C-I-I- на уровне компилятора гарантирует вызов всех деструкторов в иерархии. Сначала вызывается деструктор Square, за которым по порядку вызываются все промежуточные деструкторы вплоть до деструктора базового класса. В деструкторе базового класса содержится команда delete s. Первоначальный вызов деструктора относился к указателю s конверта , но теперь он относится к указателю s письма , который присутствует только потому, что письмо наследует от конверта , а не потому, что он содержит полезную информацию. Следовательно, этот вызов delete делать ничего не должен.

Проблема решается обнулением указателя s в письме . Теперь при вызове деструктора базового класса для письма выполняется команда delete О, которая по определению ничего не делает. Конструктор по умолчанию объявлен защищенным, поэтому он будет вызван только в процессе конструирования письма ; это единственная ситуация, в которой s присваивается ноль.

Решение получается интересным, но достаточно сложным. На практике для маскировки конструирования чаще применяются обычные Фабричные методы вместо сложных схем виртуальных конструкторов .

Строитель

Основной целью Строителя (Builder), который относится к категории паттернов создания объектов, как и только что рассмотренные Фабрики, является отделение конструирование объекта от его представления . Это означает, что процесс конструирования всегда остается одним и тем же, но полученный объект обладает несколькими разными представлениями. По БЧ главное различие между Строителем и Абстрактной фабрикой состоит в том, что Строитель создает объект за несколь-



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

В следующем примере моделируется велосипед, состоящий из различных частей в зависимости от его типа (горный, дорожный или гоночный). С каждым типом велосипеда ассоциируется свой класс Строителя, и каждый Строитель реализует интерфейс, заданный в абстрактном классе BicycleBuilder. Отдельный класс BicycleTechnician представляет объект- руководитель , описанный в книге БЧ. Этот объект использует конкретный объект BicycleBuilder для конструирования объекта Bicycle.

: C10:Bicycle.h

Определения классов для сборки велосипедов:

демонстрация паттерна Строитель.

#ifndef BICYCLE H

#define BICYCLE H

#incl ude <iostream>

#incl ude <string>

#incl ude <vector>

#incl ude <cstddef>

#include ../purge.h

using std::size t:

class BicyclePart { public:

enum BPart { FRAME. WHEEL. SEAT. DERAILLEUR. HANDLEBAR. SPROCKET. RACK. SHOCK. NPARTS }: private: BPart id:

static std::string names[NPARTS]: public:

BicyclePart(BPart bp) { id - bp: } friend std::ostreamS

operator (std::ostreamS os. const BicyclePartS bp) { return OS bp.names[bp.id]:

class Bicycle {

std::vector<BicyclePart*> parts: public:

-BicycleO { purge(parts): }

void addPart(BicyclePart* bp) { parts.push back(bp): } friend std::ostreamS

operator (std::ostreamS os. const BicycleS b) { OS { :

for(size t i = 0: i < b.parts.sizeO: ++i)

OS *b.parts[i] : return OS }:

class BicycleBuilder { protected:

Bicycle* product: public:



BicycleBuilderO { product = 0: }

void createProductO { product = new Bicycle; }

virtual void buildFrameO = 0;

virtual void buildWheelO = 0;

virtual void buildSeatO = 0;

virtual void buildDerailleurO = 0;

virtual void buildHandlebarO = 0;

virtual void buildSprocketO = 0;

virtual void buildRackO 0;

virtual void buildShockO - 0;

virtual std;;string getBikeNameO const = 0;

Bicycle* getProductO {

Bicycle* temp = product;

product =0; Сброс product

return temp;

class MountainBikeBuilder ; public BicycleBuilder { public;

void buildFrameO;

void buildWheelO;

void buildSeatO;

void buildDerailleurO;

void buildHandlebarO;

void buildSprocketO;

void buildRackO:

void buildShockO;

std;;string getBikeNameO const { return MountainBike :}

class TouringBikeBuilder ; public BicycleBuilder { public:

void buildFrameO:

void buildWheelO:

void buildSeatO;

void buildDerailleurO;

void buildHandlebarO;

void buildSprocketO;

void buildRackO;

void buildShockO;

std::string getBikeNameO const { return TouringBike : }

class RacingBikeBuilder : public BicycleBuilder { public:

void buildFrameO:

void buildWheelO:

void buildSeatO;

void buildDerailleurO;

void buildHandlebarO;

void buildSprocketO:

void buildRackO;

void buildShockO;

std::string getBikeNameO const { return RacingBike ; }

class BicycleTechnician { BicycleBuilder* builder;



1 ... 159 160 161 [ 162 ] 163 164 165 ... 196

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