![]() |
![]() | #1 |
The Reloaded Join Date: 01 2002 Location: behind the flesh and gelatinе of soft dull eyes
Posts: 3,387
Downloads: 4 Uploads: 0
Reputation: 146 | 4 | ![]()
Пару лет назад я столкнулся с ситуацией, в которой получалась не очень красивая структура кода. Пришлось подумать и улучшением её, и сейчас я хочу поделиться своим решением. Если эта проблема уже имеет известное решение, дайте ссылку. Будет интересно сравнить со своим решением. Итак, задача: имеем класс с несколькими конструкторами, с различными комбинациями параметров (т.е. несколько возможностей инизиализации объектов), и при наследовании от этого класса нужно, чтобы конструкторы наследника поддерживали все эти параметры, т.е. все варианты инициализации предка: Code: class B { public: B() {...} B(int i, double d, const std::string& s) {...} B(double d) {...} B(char* p, int n) {...} }; class D: public B { public: D() {...} D(/* the base initialization parameters: */ int i, double d, const std::string& s, /* parameters for class D: */ int x, int y): B(i, d, s) {...} D(double d, int x, int y): B(d) {...} D(char *p, int n, int x, int y): B(p, n) {...} }; Для решения этой проблемы я выделил инициализационные параметры в отдельную структуру и все конструкторы заменил одним, которому передаётся эта структура (более того, для удобства инициализации этой структуры конструкторы B перемещаются в неё): Code: class B { public: struct InitData { int i_; double d_; std::string s_; InitData(int i, double d, const std::string& s): i_(i), d_(d), s_(s) { } InitData(double d): d_(d) { } InitData(char* str, int n) s_(str, n) { } }; B() {...} B(const InitData& data) {...} }; class D: public B { public: D() {...} D(const B::InitData& baseData, int x, int y): B(baseData) {...} }; Code: class D: public class B { public: struct InitData { int x; int y; }; D() {...} D(const B::InitData& baseData, const InitData& data): B(baseData) {...} }; 1. Число параметров конструктора класса D зависит от количества предков (как прямых, в результате множественного наследования, так и косвенных, пришедших через цепочку наследований). Изменения в иерархии будут приводить к изменениям в сигнатуре конструктора, поэтому желательно перейти к конструктору с одним параметром. 2. Полученная схема не даёт возможности инициализировать по умолчанию часть базовых классов или часть членов (как базовых классов, так и нижнего класса). 3. Если каждая структура InitData повторяет члены соответствующего класса (в большинстве случаев так и будет), то можно ли избежать этой дубликации? 1. Первая проблема решается объединением всех структур InitData в одну: Code: class D: public class B1, public class B2 { public: struct InitData: B1::InitData, B2::InitData {...}; D() {...} D(const InitData& data): B1(data), B2(data) {...} }; 2. Проблему инициализации по умолчанию некторых предков или членов можно решить двумя путями. В тех случаях, когда каждому члену InitData соответствует член в соответствующем классе, можно просто инициализировать эти члены в InitData по умолчанию. В частности, если вся структура инициализирована по умолчанию, то это будет соответствовать вызову конструктора по умолчанию для соответствующего класса, и тогда конструктор B::B(const InitData& d = InitData()) полностью вытеснит конструктор по умолчанию. В остальных же случаях в структуры InitData придётся добавить специальное поле, указывающее, какие члены инициализированы нормальными данными. 3. Дублирования членов можно избежать, если каждый класс будет унаследован от своих инициализационных данных. При этом потребуется виртуальное наследование: Code: struct BData { //... }; class B: public virtual BData { //... }; struct DData: virtual BData { //... }; class D: public B, public virtual DData //виртуальное наследование на случай, если у D будут свои наследники { //... }; Last edited by Aram Hambardzumyan; 17.11.2008 at 09:05. |
![]() |
![]() |
Thread Tools | |
|
На правах рекламы: | |
![]() |
Не можно найти casino x? Тут официальный сайт
|