|
Программирование >> Разработка устойчивых систем
та будет интерпретирован как относящийся к типу 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;
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |