
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.217.4] |
![]() |
|
Страницы: (245) « Первая ... 232 233 [234] 235 236 ... 244 245 ( Перейти к последнему сообщению ) |
Сообщ.
#3496
,
|
|
|
jack128, хочешь приключений, пиши в Дельфи.
Просто конструкторы (правильнее назвать их инициализаторами) Дельфи это прямые потомки процедур инициализации ещё до-объектного Паскаля. А там никаких ограничений на порядок инициализации естественно не было. Вообще-то, если не ошибаюсь, использование виртуальных методов в конструкторах С++ "запрещено" не потому, что работает неправильно, а потому что их правильная работа не гарантируется. То есть при конструировании базового класса реализация не обязательно вызовет методы базового класса, хотя ей никто этого не запрещает. Просто обычно это лишняя работа. Если же сразу устанавливать vtable производного класса, то виртуальные вызовы будут вызывать методы производного класса, для которых ещё нет данных. Кстати, прямые вызовы виртуальных методов из конструктора обычно разрешаются статически. И есть много способов обеспечить инициализацию, подобную Дельфи. Добавлено В каком-то компиляторе такой код ![]() ![]() class Base { virtual void vf() { cout << "Конструирование Base" << endl; } void f() { vf() } Base() { f(); } } class Derived: public Base { virtual void vf() { cout << "Конструирование Derived" << endl; } Derived() { f(); } } man() { Derived d; } давал такой вывод ![]() ![]() Конструирование Base Конструирование Derived |
Сообщ.
#3497
,
|
|
|
Цитата jack128 @ Игорь, я знаю почему это плохо. Я не понимаю, почему доступ к неинициализированным членам через полиморфный вызов из конструктора - плохо. И это запрещено в с++, а вот использование кода #3489 - разрешено ? Я вообще то думал, что компилер обяжет меня метод GetData статиком задекларировать. Но нет. Предлагаешь запретить вызов нестатических методов в списке инициализации? Хм.. В принципе, можно было, как мне кажется. Думаю, исторически так сложилось. Хотя возможно, что в некоторых случаях это будет слишком сильным ограничением, которое заставит дублировать код. Но я таких примеров придумать не могу. Я так и не понял, какую связь с полиморфными вызовами ты тут видешь. |
Сообщ.
#3498
,
|
|
|
Цитата D_KEY @ Я так и не понял, какую связь с полиморфными вызовами ты тут видешь. Я так понимаю, что jack128 говорит о непоследовательности - щепетильное отношения к полиморфным вызовам и наплевательское к обращению к не инициализированным данным. |
Сообщ.
#3499
,
|
|
|
Ну тут все-таки разные ..эм.. уровни ответственности. В рассматриваемом случае все происходит в пределах класса, а не размазоно по иерархии. Хотя да, в данном случае лучше было бы как-то предупреждать/ругаться.
|
Сообщ.
#3500
,
|
|
|
Цитата D_KEY @ Но я таких примеров придумать не могу. Инициализаторы в списке выполняются последовательно (в порядке следования членов в описании класса). Поэтому можно инициализировать последующие члены на основании информации из уже инициализированных. А информация может извлекаться посредством вызовов нестатических методов. Хотя понять такой код будет непросто. ![]() ![]() class UniqueId { public: UniqueId() id(next_id()) {} get_id() { return id; } ind id; private: static int next_id() { static int store = 0; return ++store; } }; class MyObject { public: MyObject(): name(id()) {} // проще конечно было бы написать name(m_id.get_id()) // но id() здесь не может быть статическим членом int id() { return m_id.get_id(); } int name() { return m_name; } private: UniqueId m_id; string m_name; strng build_name(int id) { ... // Здесь на основе идентификатора генерируем имя } }; |
![]() |
Сообщ.
#3501
,
|
|
Цитата D_KEY @ Предлагаешь запретить вызов нестатических методов в списке инициализации? Ну вообще да. Я случайно этот код написал и был сильно удивлен, что компилятор не ругнулся. |
![]() |
Сообщ.
#3502
,
|
|
Не сочти за снобизм, это не придирки к синтетическому примеру.
Имеем класс с публичным данным. Хм. Это либо не класс, либо данные должны были быть закрыты. В первом случае последующий косяк в производном классе - на совести его автора, во втором - на совести автора базового. Производный класс наследует базовый приватно. На лицо желание превратить некласс в класс, что более вероятно. Последнее, надо полагать (иначе зачем это вообще было замышлять), скорее всего из-за (вдруг?) появившихся инвариантов, каковых не было в исходной структуре-классе. Отсюда и косяк автора производного класса: этот класс первый в иерархии, до него классов не было, поэтому он должен заботиться о сохранности своих инвариантов, а значит доступные ему данные, хоть и унаследованные, рассматривать как свои. А всё почему: получать доступ к своим данным посредством своих же методов не глупо, но глупо при этом не учитывать инвариантность, а уж тем более в конструкторах/деструкторах. Отсюда, кстати, пошло дурацкое правило во многих CodeStyle-ах на запрет вызова методов из них. Дурацкое - потому что такие баги элементарно отлавливаются на код-ревью, тогда как полный запрет на вызовы методов из конструкторов/деструкторов связывает руки программерам и зачастую вынуждает позволять просачиваться другим, более опасным ошибкам, которые даже на тестировании выявить куда сложнее. Цитата jack128 @ Во-первых, не запрещено. Полиморфный вызов "всего лишь" не покинет пределов уже сконструированной иерархии (т.е. гарантировано уже работоспособной) и на данный момент конструируемого класса (т.е. полностью под контролем кода конструктора). Во-вторых, как следствие во-первых, полиморфный вызов гарантировано не передаст управление коду, который не готов увидеть мусор на месте объекта. И более того: автор конструктора уверен, что никто не вмешается в процесс конструирования, и он полностью защищён от посягательств извне от не подконтрольного ему кода. Это одна (не единственная) из причин высокой надёжности Плюсовой объектной модели относительно человеческого фактора.Я не понимаю, почему доступ к неинициализированным членам через полиморфный вызов из конструктора - плохо. И это запрещено в с++ Тут нет не подконтрольного автору конструктора кода. Тут либо его собственный код, либо унаследованный. Цитата amk @ Он и должен такой давать. В каком-то компиляторе такой код... ...давал такой вывод... |
Сообщ.
#3503
,
|
|
|
Цитата Qraizer @ высокой надёжности Плюсовой объектной модели относительно человеческого фактора Да бросьте! ![]() ![]() |
![]() |
Сообщ.
#3504
,
|
|
Впрочем, jack128, я тут же как-то писал подробнее. Чтоб не повторяться...
Добавлено Не, даже вот это. Тут интереснее. Добавлено MyNameIsIgor, троллишь? Я не о C++, а о его объектной модели. Это как бы немножечко разные понятия. |
Сообщ.
#3505
,
|
|
|
Цитата Qraizer @ MyNameIsIgor, троллишь? Отнюдь. Цитата Qraizer @ Я не о C++, а о его объектной модели. Это как бы немножечко разные понятия. А есть ли хоть какая-то разница? Всё равно можно такие низкоуровневые "шалости" творить, что плевать на всю объектную модель. |
![]() |
Сообщ.
#3506
,
|
|
Есть, конечно. Отсутствие жёстких ограничений почти на всё позволяет сделать почти всё. Построить Дельфийную модель в частности, если вдруг приспичит. Ну, почти Дельфийную. Но вот почему-то как-то никто не строит. Я, по крайней мере, никогда не встречал за пределами VCL. Всё дело в опасности что-либо поломать при "нарушении устоев". Чем опаснее последствия, тем сложнее это сделать случайно. К примеру, одно дело спутать публичное и защищённое наследование, другое - порядок инициализации подобъектов.
Это уже другая грань С++: не навязывать жёстко ничего, для чего нет категорических абсолютов, однако мотивировать следованию "хорошим традициям". Плюсовая объектная модель не единственно возможная, а значит в некоторых случаях нежелательной. Но это не значит, что язык будет в восторге от ухода в сторону от неё. |
Сообщ.
#3507
,
|
|
|
Qraizer, так я об этом же: язык не терпит тех, кто не знает или не умеет. "Хорошие традиции" надо усвоить, правила - запомнить, тонкости - узнать. А после этого всего ещё и не ошибиться. Вот и получается, что человеческий фактор очень сильно влияет.
|
![]() |
Сообщ.
#3508
,
|
|
По-моему, мы о разном.
Добавлено Поменяй случайно порядок инициализации подобъектов, плз. |
Сообщ.
#3509
,
|
|
|
Цитата Qraizer @ Поменяй случайно порядок инициализации подобъектов, плз. Да пожалуйста ![]() ![]() ![]() struct S { int i; S() : i(i) {} }; И вот уже у нас i не инициализировано вообще. |
![]() |
Сообщ.
#3510
,
|
|
![]() |