Первые две программы выводят Derived::foo, третья выводит Base::foo.
Глубоко обежден, что поведение C++ (третья) правильное, однако интересно услышать мнение почему так сделано в CLI.
Программа C#
class Base
{
~Base()
{
foo();
}
public virtual void foo()
{
Console.WriteLine("Base::foo");
}
}
class Derived : Base
{
public overide void foo()
{
Console.WriteLine("Derived::foo");
}
}
class Program
{
public static void Main()
{
Base b = new Derived;
b = null;
GC.Collect();
}
}
Программа на C++/CLI:
ref struct Base
{
~Base()
{
foo();
}
virtual void foo()
{
Console::WriteLine("Base::foo");
}
};
ref struct Derived : Base
{
virtual void foo() override
{
Console::WriteLine("Derived::foo");
}
};
int main()
{
Base ^ b = gcnew Derived;
delete b;
}
Программа на C++:
struct Base
{
~Base()
{
foo();
}
virtual void foo()
{
}
};
struct Derived : Base
{
virtual void foo()
{
std::cout << "Derived::foo" << std::endl;
}
};
int main()
{
Base * b = new Derived;
delete b;
}
А если Derived::foo обращается к каким-то ресурсам которые уже удалены.... А говорят verifiable....
class Base
{
~Base()
{
foo();
}
public virtual void foo()
{
Console.WriteLine("Base::foo");
}
}
class Derived : Base
{
Derived () { ... }
~Derived ()
{
o.Dispose();
}
public overide void foo()
{
o.HelloWorld();
Console.WriteLine("Derived::foo");
}
DisposableObject o;
}
class Program
{
public static void Main()
{
Base b = new Derived;
b = null;
GC.Collect(); //тыдыж!!!! :(
}
}
ЗЫ Я знаю разницу между Finalizerом и деструктором Так меньше писать.
Стандартные хорошо описанные грабли С++. Правило KISS -- если структуре не нужен виртуальный деструктор -- зачем компилятору его самостоятельно прикручивать?
Здравствуйте, BitField, Вы писали:
BF>Стандартные хорошо описанные грабли С++. Правило KISS -- если структуре не нужен виртуальный деструктор -- зачем компилятору его самостоятельно прикручивать?
[... skipped ...]
PC>А если Derived::foo обращается к каким-то ресурсам которые уже удалены.... А говорят verifiable....
А нефиг в Finalize обращаться к таким ресурсам — он для освобождения чего-то, что ещё не освобождено, предназначен. И вообще — Dispose лучше вызывать из родительского Dispose, т.к. из Finalize имхо уже немного поздно это делать (курим Dispose pattern).
В общем, если проектировать правильно, то никаких гвоздей
Здравствуйте, Pavel Chikulaev, Вы писали:
PC>Я в шоке Читаю стандарт С# и С++/CLI.
PC>Первые две программы выводят Derived::foo, третья выводит Base::foo.
PC>Глубоко обежден, что поведение C++ (третья) правильное, однако интересно услышать мнение почему так сделано в CLI.
Базовый принцип — тип у объекта всегда один. Было принято волевое решение, что так — логичнее.
Вся виртуальная таблица инициализируется сразу же, еще до вызова конструктора. Кроме того, все поля автоматически инициализируются значениями по умолчанию.
Таким образом, в конструкторе мы имеем полностью рабочий объект. Точно так же и в финалайзере мы всегда работаем с полностью рабочим объектом.
Такое поведение было признано более логичным — нет разницы, откуда ты вызываешь виртуальный метод.
Кроме того, плюсовая стратегия приводила бы к многим другим неочевидным вещам — вот например, GetType(), хоть и невиртуальный, должен был бы в конструкторе возвращать не финальный тип, а тот, до которого мы "доконструировались". Иначе были бы возможны спецэффекты — вроде обнаружения через Reflection методов, которых еще нет.
Ну и много других побочных эффектов. Причем их существование ничем не оправдано — никакого риска типа "а вдруг у нас объект еще не до конца сконструирован или частично разрушен" нет.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
PC>>Глубоко обежден, что поведение C++ (третья) правильное, однако интересно услышать мнение почему так сделано в CLI. S>Базовый принцип — тип у объекта всегда один. Было принято волевое решение, что так — логичнее. S>Вся виртуальная таблица инициализируется сразу же, еще до вызова конструктора. Кроме того, все поля автоматически инициализируются значениями по умолчанию. S>Таким образом, в конструкторе мы имеем полностью рабочий объект. Точно так же и в финалайзере мы всегда работаем с полностью рабочим объектом. S>Такое поведение было признано более логичным — нет разницы, откуда ты вызываешь виртуальный метод. S>Кроме того, плюсовая стратегия приводила бы к многим другим неочевидным вещам — вот например, GetType(), хоть и невиртуальный, должен был бы в конструкторе возвращать не финальный тип, а тот, до которого мы "доконструировались". Иначе были бы возможны спецэффекты — вроде обнаружения через Reflection методов, которых еще нет. S>Ну и много других побочных эффектов. Причем их существование ничем не оправдано — никакого риска типа "а вдруг у нас объект еще не до конца сконструирован или частично разрушен" нет.
Все логично, но в С++ нет таких проблем как в CLI в четвертом примере.
ИМХО правильный подход конструирования (он даже не как в С++ )
Выделение памяти необходимое для всего объекта Base + Derived + ...
"Стандартное конструирование части Base" — все поля(члены) Base нулями и установка указателя на таблицц виртульных функции Base
"Пользовательское конструирование" части Base
"Стандартное конструирование части Derive" — все поля(члены) Derived нулями и установка указателя на таблицц виртульных функции Base
"Пользовательское конструирование" части Base
...
И соответсвенно разрушение/файнализинг
...
Установка указателя на таблицц виртульных функции Derived — части MoreDerived нет
"Пользовательское разрушение/файнализинг" части Derived
"Стандартное разрушение/файнализингчасти Derived" — все поля(члены) Derived нулями и удаление gcrootов
Установка указателя на таблицц виртульных функции Base — части Derived нет
"Пользовательское разрушение/файнализинг" части Base
"Стандартное разрушение/файнализингчасти Base " — все поля(члены) Base нулями и удаление gcrootов
Отдаем память
Что повлияло на разработчиков .NET, что не позволило им использовать этот более правильный в теоретическом и практическом ООП-смыслах.
В C++ тоже не идеал — конструирование немного не так... по понятным соображениям производительность — как никак низкий уровень, дважды нулями нехочется. Но CLI... и так все тормозит... почему бы нет?
А GetType это вообще идиотизм... ООП блин... typeid без какого-либо членства в С++ умудряется делать все то же самое... (ну или почти ... но эт на самом деле не важно...)
Очень жаль, что разрботчики .NET не читали Design & Evolution of C++ — много бы проблем избежали типа не совмещять понятия access и overload.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Pavel Chikulaev, Вы писали:
PC>>Я в шоке Читаю стандарт С# и С++/CLI.
PC>>Первые две программы выводят Derived::foo, третья выводит Base::foo.
PC>>Глубоко обежден, что поведение C++ (третья) правильное, однако интересно услышать мнение почему так сделано в CLI. S>Базовый принцип — тип у объекта всегда один. Было принято волевое решение, что так — логичнее.
Он и в C++ всегда один. Просто в С++ объекты конструируются, а в .Net инициализируются после конструирования по-умолчанию. В этом разница. В .Net нет конструкторов класса, а есть инициализаторы класса. Эквивалент в C++ -- двухфазная инициализация.
class C
{
public:
C();
void init(int a,int b,int c);
};
C c;
c.init(1,2,3);
И это не терминологическая разница. Кстати, к вопросу о терминологии. Правильная терминология не должна скрывать суть вещей и тем более выдавать одно за другое.
S>Вся виртуальная таблица инициализируется сразу же, еще до вызова конструктора. Кроме того, все поля автоматически инициализируются значениями по умолчанию. S>Таким образом, в конструкторе мы имеем полностью рабочий объект. Точно так же и в финалайзере мы всегда работаем с полностью рабочим объектом. S>Такое поведение было признано более логичным — нет разницы, откуда ты вызываешь виртуальный метод.
Есть. Она есть объективно и устранить эту разницу нельзя. Просто разработчики .Net скрыли проблему за счет отказа от возможностей.
Впрочем, для облегчённого языка подобные подходы вполне оправданы.
S>Кроме того, плюсовая стратегия приводила бы к многим другим неочевидным вещам — вот например, GetType(), хоть и невиртуальный, должен был бы в конструкторе возвращать не финальный тип, а тот, до которого мы "доконструировались". Иначе были бы возможны спецэффекты — вроде обнаружения через Reflection методов, которых еще нет.
+
S>Ну и много других побочных эффектов. Причем их существование ничем не оправдано — никакого риска типа "а вдруг у нас объект еще не до конца сконструирован или частично разрушен" нет.
Неверно. Корректность состояния объекта не сводится к тому -- проинициализированы его поля или нет.
class Base
{
public Base() { doIt(); }
public virtual void doIt() {}
}
class Derived : Base
{
SomeClass obj;
public Derived()
{
obj=new SomeClass();
}
public override void doIt() { obj.method(); }
}
Здравствуйте, Pavel Chikulaev, Вы писали:
PC>Что повлияло на разработчиков .NET, что не позволило им использовать этот более правильный в теоретическом и практическом ООП-смыслах.
"Моё кунг-фу лучше, чем твоё кунт-фу"? Что такое "правильное ООП", вообще? Например, CLOS (Common Lisp Object System) тоже ООП, хотя там нет методов (есть generic functions) и все слоты (aka поля) public.
PC>В C++ тоже не идеал — конструирование немного не так... по понятным соображениям производительность — как никак низкий уровень, дважды нулями нехочется. Но CLI... и так все тормозит... почему бы нет?
Вот это "и так всё тормозит", наверное, не совсем корректно без ссылок на тесты. Или тормозит по определению?
Эта по сути своей флеймовая тема уже не раз поднималась, и, как известно, CLR не то чтобы очень и тормозит...
PC>А GetType это вообще идиотизм... ООП блин... typeid без какого-либо членства в С++ умудряется делать все то же самое... (ну или почти ... но эт на самом деле не важно...)
"Почти" не считается. Я бы сказал — typeid сотоварищи и рядом не валялись с reflection.
Кстати, почему это GetType() идиотизм? Почему плохо всегда знать тип объекта? Или, если бы этот метод был статическим, тебе было бы легче?
PC>Очень жаль, что разрботчики .NET не читали Design & Evolution of C++ — много бы проблем избежали типа не совмещять понятия access и overload.
Вот с этим совершенно не согласен. Во-первых, наверняка читали Во-вторых, им удалось избежать многих проблем C++ (довольно сложный синтаксис, обязательная перекомпиляция всего в процессе билда, отсутствие чего-то вроде сборки в .NET FW, пресловутые memory leaks).
Дизайн CLI отнюдь не случаен. Поверь — товарищи разработчики долго взвешивали все "за" и "против". И, я думаю, получилось у них очень неплохо.
Здравствуйте, Pavel Chikulaev, Вы писали:
PC>Все логично, но в С++ нет таких проблем как в CLI в четвертом примере.
Есть. Просто ты их не замечаешь. Ты искусственно придумал пример, при котором финалайзер базового типа начинает заниматься фигней. Финалайзер вообще стоит писать с большой осторожностью, т.к. порядок финализации не определен. Независимо от того, вызывается ли виртуальный метод, и был ли вызван финалайзер потомка.
Для начала рекомендую несколько освоиться с индетерминистической финализацией как таковой. Она сводится не только к отсутствию возможности вызвать деструктор напрямую. Есть и другие ограничения. В аналогичном случае ты бы рисковал получить то же самое, т.к. вместо вызова деструктора у тебя был бы вызов классического виртуального метода Dispose. И он точно так же позвал бы Derived::Foo, который бы успешно обратился к уже отдиспозенному Derived::o. И получил бы исключение ObjectDisposed.
PC>ИМХО правильный подход конструирования (он даже не как в С++ ) PC>
PC>Выделение памяти необходимое для всего объекта Base + Derived + ... PC>"Стандартное конструирование части Base" — все поля(члены) Base нулями и установка указателя на таблицц виртульных функции Base PC>"Пользовательское конструирование" части Base PC>"Стандартное конструирование части Derive" — все поля(члены) Derived нулями и установка указателя на таблицц виртульных функции Base PC>"Пользовательское конструирование" части Base PC>... PC>
И чего он позволит достичь? Зачем, собственно, этот геморрой? PC>И соответсвенно разрушение/файнализинг PC>
PC>... PC>Установка указателя на таблицц виртульных функции Derived — части MoreDerived нет PC>"Пользовательское разрушение/файнализинг" части Derived PC>"Стандартное разрушение/файнализингчасти Derived" — все поля(члены) Derived нулями и удаление gcrootов PC>Установка указателя на таблицц виртульных функции Base — части Derived нет PC>"Пользовательское разрушение/файнализинг" части Base PC>"Стандартное разрушение/файнализингчасти Base " — все поля(члены) Base нулями и удаление gcrootов PC>Отдаем память PC>
PC>Что повлияло на разработчиков .NET, что не позволило им использовать этот более правильный в теоретическом и практическом ООП-смыслах.
Здравый смысл и огромный опыт. PC>В C++ тоже не идеал — конструирование немного не так... по понятным соображениям производительность — как никак низкий уровень, дважды нулями нехочется. Но CLI... и так все тормозит... почему бы нет?
PC>А GetType это вообще идиотизм... ООП блин... typeid без какого-либо членства в С++ умудряется делать все то же самое... (ну или почти ... но эт на самом деле не важно...)
А, вот теперь мне все понятно. Я рекомендую тебе воздержаться от критики дотнета до тех пор, пока ты не получишь достаточный опыт. Нельзя слепо переносить опыт из одной среды в другую. GetType() настолько круче, чем typeid, что это даже обсуждать бессмысленно. На нем построено очень много чего в дотнете. Но ты пока что не видишь всей этой мощи, потому как смотришь на дотнет сквозь танковую смотровую щель С++.
PC>Очень жаль, что разрботчики .NET не читали Design & Evolution of C++ — много бы проблем избежали типа не совмещять понятия access и overload.
Уверяю тебя — читали. И изучили не только С++, а еще много языков.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Pavel Chikulaev, Вы писали:
PC>Там еще очень много подстав... Статью что-ли написать?
PC>Например: PC>
PC> d.foo(4.35); //не ок :)) выведет float
PC>
PC>Hidebysig in action.
Да, уж. Подставища еще та. Я бы даже сказал клинический случай.
Однако как плюсы менталитет плющат.
Ведь даже в голову не прийдет, что решения в дизайне языков бывают разные? И уж темболее не задумываться же на счет того, что дизайн любимого языка может оказаться кривым?
Что странного с того, что методы не скрываются если они имеют разные сигнатуры? Ну, напиши:
d.foo((int)4.35);
и вызовется нужный метод.
Кстати, Шарп на твой код пошлет далеко и на долго, так как 4.35 в нем квалифицируется как double, а автоматическое понижающее приведение типов в нем запрещено. Но так:
d.foo(4.35F);
все пройдет на ура.
ЗЫ
Кстати, это баян. Вопрос обсуждался сто лет назад.
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Попробуй заняться статистикой... подсчитать количество обратившихся в форумы со случаями подобными описаным тобой на Шарпе, и со случаями вроде "почему не вызвалась моя виртуальная функция в С++?" и "почему виртуальный конструктор не виртуальный?".
А потом за одно подсчитай сколько обратилось с вопросом "почему в С++ не вызвался деструктор класса наследника?". Ведь ты не указал, что у Base деструктор виртуальный, но тем не менее вызывашь его у типа приведенного к базовому.
Когда подвидешь результаты статистического исследования подумай "почему оно оказалось не в пользу С++?".
ЗЫ
Почти уверен отевет на все вопросы будет "да они все ламеры..."
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
О! Еще одна попытка объяснить почему на С++ программировать безопаснее, быстрее и удобнее чем на C#. Радует только то, что появилось хоть каое-то разнообразие. С++ vs. C++/CLI это все же свежо!
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Pavel Chikulaev, Вы писали:
PC>Очень жаль, что разрботчики .NET не читали Design & Evolution of C++ — много бы проблем избежали типа не совмещять понятия access и overload.
Не, ну, все можно понять, в конце концов объяснить складом характера. Но чтобы вот так посоветовать почитать книг человеку создавшему не один популярнийший ООЯ — это ж какой самоуверенностью нужно обладать?!
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Шахтер, Вы писали:
Ш>Он и в C++ всегда один. Просто в С++ объекты конструируются, а в .Net инициализируются после конструирования по-умолчанию. В этом разница.
Нет в дотнете кострукторов по-умолчанию. Есть инициализация экземпляра системой которая заключается в обнулении памяти (и то реально обнуляется область кучи) и засовывании ссылки на информацию о типе в начало объекта.
Ш>В .Net нет конструкторов класса, а есть инициализаторы класса.
Как раз "конструкторов классов" в дотнете есть. Только делают они не то о чем ты думашь. Они вызываются при первом обращении к классу.
А ты говоришь о конструкторах экземпляров. И они тоже есть. Ну, а то что для С++-ника странно выглядит проинициализированные vtbl и т.п. (кстати, ее как раз в дотнете в общем-то нет ), так это просто проблемы стереотипов.
Ш>Эквивалент в C++ -- двухфазная инициализация.
Ш>
Это не совсем эквивалент. Отличий два:
1. "C();" физически нет.
2. При исключении в "init" в дотнете невозможно будет получить ссылку н объект.
Ш>И это не терминологическая разница. Кстати, к вопросу о терминологии. Правильная терминология не должна скрывать суть вещей и тем более выдавать одно за другое.
Ну, да. Далее начинаем спорить где нет конструторов. Например, заявляем, что в С++ конструкторов нет, так как это просто методы которые вызываются для инициализации отдельных областей объекта.
Ш>Есть. Она есть объективно и устранить эту разницу нельзя. Просто разработчики .Net скрыли проблему за счет отказа от возможностей.
По больше бы таких проблем. Ну, что бы о них говорили теоретики и не видили в упор практики. А то я вот за все время ни одного рельного случая наступания на данные грабли не видел, а вот проблемы с идиально спроектированным С++ в этой области наблюдаются постоянно.
Ш>Впрочем, для облегчённого языка подобные подходы вполне оправданы.
Это какй из них облегченный? С++/CLI, что ли? Или MSIL?
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
PC>>Hidebysig in action. VD>Да, уж. Подставища еще та. Я бы даже сказал клинический случай.
Для С++/CLI да.
VD>Однако как плюсы менталитет плющат.
П. 5 !!!
VD>Ведь даже в голову не прийдет, что решения в дизайне языков бывают разные? И уж темболее не задумываться же на счет того, что дизайн любимого языка может оказаться кривым?
Очень даже придет... млин см. п. 5!!!
VD>Кстати, Шарп на твой код пошлет далеко и на долго, так как 4.35 в нем квалифицируется как double, а автоматическое понижающее приведение типов в нем запрещено. Но так:
Очепятка, я стандарт С# прочитал, и пишу на нем тоже, и кое-что понимаю...
Здравствуйте, Oyster, Вы писали:
PC>>Что повлияло на разработчиков .NET, что не позволило им использовать этот более правильный в теоретическом и практическом ООП-смыслах. O>"Моё кунг-фу лучше, чем твоё кунт-фу"? Что такое "правильное ООП", вообще? Например, CLOS (Common Lisp Object System) тоже ООП, хотя там нет методов (есть generic functions) и все слоты (aka поля) public.
Наследование сделано не правильно...
PC>>В C++ тоже не идеал — конструирование немного не так... по понятным соображениям производительность — как никак низкий уровень, дважды нулями нехочется. Но CLI... и так все тормозит... почему бы нет?
O>Вот это "и так всё тормозит", наверное, не совсем корректно без ссылок на тесты. Или тормозит по определению?
Ок из-за безопасности... будем считать, что не тормозит...
PC>>А GetType это вообще идиотизм... ООП блин... typeid без какого-либо членства в С++ умудряется делать все то же самое... (ну или почти ... но эт на самом деле не важно...)
O>"Почти" не считается. Я бы сказал — typeid сотоварищи и рядом не валялись с reflection.
млин зачем делать членом, то что могло им не быть... Например в C++3x элементарно можно добавиь reflection в std::type_info...
O>Кстати, почему это GetType() идиотизм? Почему плохо всегда знать тип объекта? Или, если бы этот метод был статическим, тебе было бы легче?
Я и из typeid знаю... не так хорошо, но знаю
Ладно про это проехали, С++ и без reflection хорошо живет...
PC>>Очень жаль, что разрботчики .NET не читали Design & Evolution of C++ — много бы проблем избежали типа не совмещять понятия access и overload. O>Вот с этим совершенно не согласен. Во-первых, наверняка читали Во-вторых, им удалось избежать многих проблем C++ (довольно сложный синтаксис, обязательная перекомпиляция всего в процессе билда, отсутствие чего-то вроде сборки в .NET FW, пресловутые memory leaks).
Я про CLI, а не про шарп. Наследние С и только. Memory leaks у некоторых и без GC нет...
O>Дизайн CLI отнюдь не случаен. Поверь — товарищи разработчики долго взвешивали все "за" и "против".
Так вот эти "за" и "против" о которых я спрашивал никто говорит не собирается.
O>И, я думаю, получилось у них очень неплохо.
Кое-что да, кое-что нет...
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Pavel Chikulaev, Вы писали:
PC>>Все логично, но в С++ нет таких проблем как в CLI в четвертом примере.
S>Есть. Просто ты их не замечаешь. Ты искусственно придумал пример, при котором финалайзер базового типа начинает заниматься фигней.
Ок придумай искусственный пример где С++ с его семантикой смены динамического типа в дторе подведет. Жду.
S>Финалайзер вообще стоит писать с большой осторожностью, т.к. порядок финализации не определен. Независимо от того, вызывается ли виртуальный метод, и был ли вызван финалайзер потомка.
Да я понимаю это. Это безусловно лишь теоретический вопрос.
S>Для начала рекомендую несколько освоиться с индетерминистической финализацией как таковой. Она сводится не только к отсутствию возможности вызвать деструктор напрямую. Есть и другие ограничения. В аналогичном случае ты бы рисковал получить то же самое, т.к. вместо вызова деструктора у тебя был бы вызов классического виртуального метода Dispose. И он точно так же позвал бы Derived::Foo, который бы успешно обратился к уже отдиспозенному Derived::o. И получил бы исключение ObjectDisposed.
Почему ты так уверен, что я это не понимаю?
PC>>ИМХО правильный подход конструирования (он даже не как в С++ ) PC>>
PC>>Выделение памяти необходимое для всего объекта Base + Derived + ... PC>>"Стандартное конструирование части Base" — все поля(члены) Base нулями и установка указателя на таблицц виртульных функции Base PC>>"Пользовательское конструирование" части Base PC>>"Стандартное конструирование части Derive" — все поля(члены) Derived нулями и установка указателя на таблицц виртульных функции Base PC>>"Пользовательское конструирование" части Base PC>>... PC>>S>И чего он позволит достичь? Зачем, собственно, этот геморрой?
Потому что это самый правильный вариант, но в чистом виде он нигде не используется (ни в С++ ни CLS)
PC>>И соответсвенно разрушение/файнализинг PC>>
PC>>... PC>>Установка указателя на таблицц виртульных функции Derived — части MoreDerived нет PC>>"Пользовательское разрушение/файнализинг" части Derived PC>>"Стандартное разрушение/файнализингчасти Derived" — все поля(члены) Derived нулями и удаление gcrootов PC>>Установка указателя на таблицц виртульных функции Base — части Derived нет PC>>"Пользовательское разрушение/файнализинг" части Base PC>>"Стандартное разрушение/файнализингчасти Base " — все поля(члены) Base нулями и удаление gcrootов PC>>Отдаем память PC>> PC>>Что повлияло на разработчиков .NET, что не позволило им использовать этот более правильный в теоретическом и практическом ООП-смыслах. S>Здравый смысл и огромный опыт.
Сомневаюсь...
PC>>В C++ тоже не идеал — конструирование немного не так... по понятным соображениям производительность — как никак низкий уровень, дважды нулями нехочется. Но CLI... и так все тормозит... почему бы нет?
PC>>А GetType это вообще идиотизм... ООП блин... typeid без какого-либо членства в С++ умудряется делать все то же самое... (ну или почти ... но эт на самом деле не важно...) S>А, вот теперь мне все понятно. Я рекомендую тебе воздержаться от критики дотнета до тех пор, пока ты не получишь достаточный опыт. Нельзя слепо переносить опыт из одной среды в другую. GetType() настолько круче, чем typeid, что это даже обсуждать бессмысленно. На нем построено очень много чего в дотнете.
П. 5. Я ЭТО МЛИН ЗНАЮ! В скобках написано, что reflection не учитывается... S>Но ты пока что не видишь всей этой мощи, потому как смотришь на дотнет сквозь танковую смотровую щель С++.
А ты уверен, что щель с моей стороны? Я нет.
PC>>Очень жаль, что разрботчики .NET не читали Design & Evolution of C++ — много бы проблем избежали типа не совмещять понятия access и overload. S>Уверяю тебя — читали. И изучили не только С++, а еще много языков.
И все в .NET замечательно да? фанатизм какой-то...
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Pavel Chikulaev, Вы писали:
VD>Попробуй заняться статистикой... подсчитать количество обратившихся в форумы со случаями подобными описаным тобой на Шарпе, и со случаями вроде "почему не вызвалась моя виртуальная функция в С++?" и "почему виртуальный конструктор не виртуальный?".
Для домохозяек это безусловно аргумент...
VD>А потом за одно подсчитай сколько обратилось с вопросом "почему в С++ не вызвался деструктор класса наследника?". Ведь ты не указал, что у Base деструктор виртуальный, но тем не менее вызывашь его у типа приведенного к базовому.
"Pay as you go" а не "а мне пофиг сколько программа жрет памяти, когда надо удалится, а то, что не детерминированно и исходный код как на ладони это безусловно фигня".
VD>Почти уверен отевет на все вопросы будет "да они все ламеры..."
давай я сам отвечу, а?
Здравствуйте, Pavel Chikulaev, Вы писали:
PC>Наследование сделано не правильно...
См. предыдущие (и последующие) топики, а то твердить одно и то же надоело.
PC>Ок из-за безопасности... будем считать, что не тормозит...
PC>млин зачем делать членом, то что могло им не быть... Например в C++3x элементарно можно добавиь reflection в std::type_info...
А зачем не делать членом то, что может им быть? В System.Object есть ещё Equals, GetHashCode и ToString — их, наверное, тоже стоит убрать?...
Информация о типе объекта всё равно всегда связана с объектом. Её всегда можно получить у объекта — так что почему бы не сделать соответствующий метод (который, к тому же, используется во многих местах в FCL и который совершенно не получится подменить)?
PC>Я и из typeid знаю... не так хорошо, но знаю PC>Ладно про это проехали, С++ и без reflection хорошо живет...
Да просто отлично живёт. Сериализация, например, без reflection делается на раз-два-три совершенно без геморроя в виде тучи классов и макросов, правда?
PC>Я про CLI, а не про шарп. Наследние С и только. Memory leaks у некоторых и без GC нет...
Аргументы? Я так понял, пока что твой единственный аргумент это "неправильное" наследование?
PC>Так вот эти "за" и "против" о которых я спрашивал никто говорит не собирается.
Изучи вопрос. Почитай книжки (Рихтера, например), блоги, статьи. Я для тебя искать информацию не собираюсь (времени нет), но вот кое-что нашёл: http://www.artima.com/intv/choices.html (не в тему, так как там CLR vs JVM, а не CLR vs Godlike C++)
PC>Кое-что да, кое-что нет...
Согласен — CLI, C# и FCL не лишены недостатков. Но... покажи мне идеальный продукт
Здравствуйте, Pavel Chikulaev, Вы писали:
VD>>Да, уж. Подставища еще та. Я бы даже сказал клинический случай. PC>Для С++/CLI да.
И чем же это подстава то? Это как раз в С++ вместо перегрузки по типу перекрытие на необъяснимых основаниях.
VD>>Однако как плюсы менталитет плющат. PC>П. 5 !!!
VD>>Ведь даже в голову не прийдет, что решения в дизайне языков бывают разные? И уж темболее не задумываться же на счет того, что дизайн любимого языка может оказаться кривым? PC>Очень даже придет... млин см. п. 5!!!
И где же ты углядел то п.5? Я же не виноват, что совершенно логичное поведение ты счет "подставой", а страннейшее С++-ное нормальным.
Как это еще объяснить? Это именно влияние языка на менталитет. Ты просто привык к изращенному миру и смотришь на нормальный мир как на нечто ненормальное.
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Pavel Chikulaev, Вы писали:
PC>Наследование сделано не правильно...
А вообще бывает что-то в программироании правильное и при этом не похожее на С++?
O>>"Почти" не считается. Я бы сказал — typeid сотоварищи и рядом не валялись с reflection. PC>млин зачем делать членом, то что могло им не быть... Например в C++3x элементарно можно добавиь reflection в std::type_info...
А зачем что-то засовывать в даль если это неотемлемая часть любого объекта? Это чему-то помешает? Или снова ранушение принципов отрытозакрытости?
O>>Кстати, почему это GetType() идиотизм? Почему плохо всегда знать тип объекта? Или, если бы этот метод был статическим, тебе было бы легче? PC>Я и из typeid знаю... не так хорошо, но знаю
Это знание бесценно, потому что бесполезно.
PC>Ладно про это проехали, С++ и без reflection хорошо живет...
Ага. Видимо по этому в С++ХХХ только и разговоры о нем.
PC>Я про CLI, а не про шарп. Наследние С и только. Memory leaks у некоторых и без GC нет...
И в чем же наследие С то выражается?
O>>Дизайн CLI отнюдь не случаен. Поверь — товарищи разработчики долго взвешивали все "за" и "против". PC>Так вот эти "за" и "против" о которых я спрашивал никто говорит не собирается.
Ты извини, но от тебя исходит поток догм. Ты похоже привык к штампам С++ и все непохожее всопринимашь как неверные решения. Между тем обоснований в общем-то нет. Только сожаления о том, что кто-то великий труд граблестроителей не прочел и, что методы у объектов — это идиотизм и наследие С.
O>>И, я думаю, получилось у них очень неплохо. PC>Кое-что да, кое-что нет...
Ну, так и привел бы обоснованное описание того что нет. А не рассуждения о идиотизме и пробелах в образовании. Вот привести то что прошляпил Страуструп можно легко, только это уже будет баян с бородой. Тут этого море.
Из C++/CLI попытались сделать современный язык сохранив совместимость с С++. Понятно, что совмещать ужа с ежом не простое занятие. Лично я прохладно отношусь к C++/CLI, но я прекрасно понимаю какую работу люди сделали.
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
PC>>Для С++/CLI да. VD>И чем же это подстава то? Это как раз в С++ вместо перегрузки по типу перекрытие на необъяснимых основаниях.
Что для ref class одни правила, для class другие. И всё. Не больше не меньше. Подстава для тех, кто переходит с C++ на C++/CLI.
VD>>>Ведь даже в голову не прийдет, что решения в дизайне языков бывают разные? И уж темболее не задумываться же на счет того, что дизайн любимого языка может оказаться кривым? PC>>Очень даже придет... млин см. п. 5!!!
VD>Как это еще объяснить? Это именно влияние языка на менталитет. Ты просто привык к изращенному миру и смотришь на нормальный мир как на нечто ненормальное.
Млин опять! Или тут так принято?
Здравствуйте, Oyster, Вы писали:
O>Здравствуйте, Pavel Chikulaev, Вы писали:
PC>>Наследование сделано не правильно... O>См. предыдущие (и последующие) топики, а то твердить одно и то же надоело
Ок
PC>>млин зачем делать членом, то что могло им не быть... Например в C++3x элементарно можно добавиь reflection в std::type_info...
O>А зачем не делать членом то, что может им быть? В System.Object есть ещё Equals, GetHashCode и ToString — их, наверное, тоже стоит убрать?...
потому что если доступ private и protected и остальные не нужен — лучше не член. Хотя CLS уж слишком ООП, наверно не обойтись. Ладно проехали.
O>Информация о типе объекта всё равно всегда связана с объектом. Её всегда можно получить у объекта — так что почему бы не сделать соответствующий метод (который, к тому же, используется во многих местах в FCL и который совершенно не получится подменить)?
O> Да просто отлично живёт. Сериализация, например, без reflection делается на раз-два-три совершенно без геморроя в виде тучи классов и макросов, правда?
Да.
PC>>Я про CLI, а не про шарп. Наследние С и только. Memory leaks у некоторых и без GC нет... O>Аргументы? Я так понял, пока что твой единственный аргумент это "неправильное" наследование?
Еще будут... жди.
PC>>Так вот эти "за" и "против" о которых я спрашивал никто говорит не собирается. O>Изучи вопрос. Почитай книжки (Рихтера, например), блоги, статьи. Я для тебя искать информацию не собираюсь (времени нет), но вот кое-что нашёл: http://www.artima.com/intv/choices.html (не в тему, так как там CLR vs JVM, а не CLR vs Godlike C++)
Читал... Просто похоже именно это никого не волнует...
PC>>Кое-что да, кое-что нет... O>Согласен — CLI, C# и FCL не лишены недостатков. Но... покажи мне идеальный продукт
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Pavel Chikulaev, Вы писали:
PC>>Наследование сделано не правильно...
VD>А вообще бывает что-то в программироании правильное и при этом не похожее на С++?
Да Python, D
O>>>"Почти" не считается. Я бы сказал — typeid сотоварищи и рядом не валялись с reflection. PC>>млин зачем делать членом, то что могло им не быть... Например в C++3x элементарно можно добавиь reflection в std::type_info...
O>>>Кстати, почему это GetType() идиотизм? Почему плохо всегда знать тип объекта? Или, если бы этот метод был статическим, тебе было бы легче? PC>>Я и из typeid знаю... не так хорошо, но знаю VD>Это знание бесценно, потому что бесполезно.
PC>>Ладно про это проехали, С++ и без reflection хорошо живет... VD>Ага. Видимо по этому в С++ХХХ только и разговоры о нем.
Его не будет. никогда. Да и С++ и CLS не конкуренты вообще...
PC>>Я про CLI, а не про шарп. Наследние С и только. Memory leaks у некоторых и без GC нет... VD>И в чем же наследие С то выражается?
95% косяков С++ от пришли из С и от них не избавиться
VD>Из C++/CLI попытались сделать современный язык сохранив совместимость с С++. Понятно, что совмещать ужа с ежом не простое занятие. Лично я прохладно отношусь к C++/CLI, но я прекрасно понимаю какую работу люди сделали.
+1
Здравствуйте, Pavel Chikulaev, Вы писали:
O>>А зачем не делать членом то, что может им быть? В System.Object есть ещё Equals, GetHashCode и ToString — их, наверное, тоже стоит убрать?... PC>потому что если доступ private и protected и остальные не нужен — лучше не член. Хотя CLS уж слишком ООП, наверно не обойтись. Ладно проехали.
То CLS слишком ООП, то CLI не ООП...
Кстати, причём тут Common Language Specification? Может ты имел в виду FCL? Или даже CLR/CLI?
O>> Да просто отлично живёт. Сериализация, например, без reflection делается на раз-два-три совершенно без геморроя в виде тучи классов и макросов, правда? PC>Да.
Ок. Предоставь пример такой мегабиблиотеки для C++ — я хотел бы сериализовать/десериализовать что-то вроде std::set (раз уж он упоминался) — т.е. обюъекты типов из стандартной библиотеки — и объекты своих типов.
Все библиотеки для сериализации (буст и ручные поделки), что я видел до сих пор, изобилуют макросами, которые девелопер вынужден пихать в свои классы. А насчёт сериализации и стандартных типов... вообще не видел.
O>>Аргументы? Я так понял, пока что твой единственный аргумент это "неправильное" наследование? PC>Еще будут... жди.
Ждю.
PC>Читал... Просто похоже именно это никого не волнует...
Здравствуйте, Pavel Chikulaev, Вы писали:
PC>Что для ref class одни правила, для class другие. И всё. Не больше не меньше. Подстава для тех, кто переходит с C++ на C++/CLI.
Думашь, это может вызвать какие-то проблемы? Сдается мне, что С++-ник просто не будет так перекрывать методы зная о подвохе.
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Pavel Chikulaev, Вы писали:
PC>Да Python, D
Спорные утверждения. Области видимости отбивками, отсуствие деклараций переменных и т.п. вряд ли можно назвать правильным.
PC>>>Ладно про это проехали, С++ и без reflection хорошо живет... VD>>Ага. Видимо по этому в С++ХХХ только и разговоры о нем. PC>Его не будет. никогда. Да и С++ и CLS не конкуренты вообще...
Кого? Нового стандарта? Это конечно возможно. А вот если он все таки случится, то уверен, что аналог рефлекшона там будет. Не даром этим вопросом сам Страуструп занимался.
PC>>>Я про CLI, а не про шарп. Наследние С и только. Memory leaks у некоторых и без GC нет... VD>>И в чем же наследие С то выражается? PC>95% косяков С++ от пришли из С и от них не избавиться
А, так ты о С++? А из контекста можно подумать, что о CLI. Ну, тут можно только посочувствовать. Вот твой любимый Ди хороший пример того как оставаясь совместимым с С не загрести всех косяков. Сдается мне, что дело все же было в первую очередь в непродуманности дизайна языка. Если бы напрячься, то 99% косяков можно было обойти.
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Pavel Chikulaev, Вы писали:
VD>>Попробуй заняться статистикой... подсчитать количество обратившихся в форумы со случаями подобными описаным тобой на Шарпе, и со случаями вроде "почему не вызвалась моя виртуальная функция в С++?" и "почему виртуальный конструктор не виртуальный?". PC>Для домохозяек это безусловно аргумент...
Интересно почему поклонники С++ так часто позволяют себе стольк высокомерные фразы. Не знашь частом?
Хотя аналогии вряд ли можно счесть за аргумент, но мне почему-то все время хочется провести следующую аналогию.
Сидит орел и критикует мерседес шестисотый. Мол неповоротливый. Бензин жрет. Едешь под 250, а скорость не чувствуется. Те кто его водит даже не знают где в машике находится топливный фильтр. То ли дело наш жигуль. 250 конечно не пойдет, но и на 120 ветер так свистит, что адреналин переполняет. Бензина жрет мало. А уж как будешь в крабюраторах и другой дрибидени разбираться?... В общем, зверь-машина. Это вам не это ламерские шестесотые...
Вот так же тут. Сначала поговорили про гипотетические проблемы, а потом поняв, что претензии надуманные наклеили ярлычок "для домохозяек".
А вот другой бы ярлычек пришпилил. Это для тех кто любит комфорт и умеет ценить свое время и нервы.
Возвращась к исходному вопросу скажу, что реализация кострукторов и деструкторов в С++ за многие годы доказала свою неинтуитивность и усеянность граблями. То что отдельные личности научились обходить искусно припрятанные грабли еще не значит, ничего не значит. Вот люди создавая другой язык и попытались избавиться от известных граблей. В целом у них это получилось. Но если бы они не гнались за похожестью на С++, то получилось бы еще лучше. А то ведь приходится объяснять, что финалайзер и диструктор две большие разницы. В общем, в данном случае похожесть сиграла плохую роль.
VD>>А потом за одно подсчитай сколько обратилось с вопросом "почему в С++ не вызвался деструктор класса наследника?". Ведь ты не указал, что у Base деструктор виртуальный, но тем не менее вызывашь его у типа приведенного к базовому. PC>"Pay as you go" а не "а мне пофиг сколько программа жрет памяти, когда надо удалится, а то, что не детерминированно и исходный код как на ладони это безусловно фигня".
Что-то я не оценил этого перехода. Обсуждали вроде деструкторы и финалайзеры.
VD>>Почти уверен отевет на все вопросы будет "да они все ламеры..." PC>давай я сам отвечу, а?
Давай. Но про домохозяек ты уже сказал.
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Pavel Chikulaev, Вы писали:
PC>И все в .NET замечательно да? фанатизм какой-то...
Не, не все. И если ты спросишь о проблемах, то тебе о них расскажут. Но ты пытаться свои догмы представить как чужие проблемы. И удивляешся находя не понимаение.
ЗЫ
Вообще все эти ВС. уже надоели. Я бы еще понял если кто-то разобравшись в пробелме начал серьезное, спокойное и аргументированное обсуждение. Да ведь нет. Все всегда своидстя к остаиванию догм без единого аргумента. Неважные вещи обсасываются как будто от них завист жизнь. А интересные сложные вопросы вообще не поднимаются.
... << RSDN@Home 1.2.0 alpha rev. 620>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Oyster wrote: > Ок. Предоставь пример такой мегабиблиотеки для C++ — я хотел бы > сериализовать/десериализовать что-то вроде std::set (раз уж он > упоминался) — т.е. обюъекты типов из стандартной библиотеки — и объекты > своих типов
А чего его представлять?? У меня уже давно работает:
Cyberax wrote: > А чего его представлять?? У меня уже давно работает:
Кстати, это как раз Boost.S11N. Для всех стандартных контейнеров там
поддержка есть, а также еще для Boost.Graph, Boost.SmartPtr и т.п.
Здравствуйте, Pavel Chikulaev, Вы писали:
S>>Есть. Просто ты их не замечаешь. Ты искусственно придумал пример, при котором финалайзер базового типа начинает заниматься фигней. PC>Ок придумай искусственный пример где С++ с его семантикой смены динамического типа в дторе подведет. Жду.
Как нефиг делать.
class Base
{
private:
Handle m_fileHandle;
protected:
virtual void Close()
{
CloseHandle(m_fileHandle);
}
virtual ~Base()
{
Close(); //
}
}
class Derived : public Base
{
private:
void* m_buffer;
virtual void Close()
{
delete[] m_buffer;
Base::Close();
}
}
Я намеренно поскипал код конструкторов и методов Open для краткости. Поясню: наш класс реализует переоткрываемый ресурс. Его можно закрыть и переоткрыть вручную, а можно потерять в конструкторе. В данном варианте у нас Derived::Close() не будет вызван при разрушении Derived. Несмотря на то, что мы вызываем виртуальный метод из виртуального метода. Ок, допустим я в отчаянии прочел доку и узнал про эти грабли. Я дописываю деструктор ~Derived с вызовом Close. Отлично — теперь у меня дважды вызывается Base::Close().
S>>Для начала рекомендую несколько освоиться с индетерминистической финализацией как таковой. Она сводится не только к отсутствию возможности вызвать деструктор напрямую. Есть и другие ограничения. В аналогичном случае ты бы рисковал получить то же самое, т.к. вместо вызова деструктора у тебя был бы вызов классического виртуального метода Dispose. И он точно так же позвал бы Derived::Foo, который бы успешно обратился к уже отдиспозенному Derived::o. И получил бы исключение ObjectDisposed. PC>Почему ты так уверен, что я это не понимаю?
Потому, что ты пишешь о разрушении объекта как о детерминистическом процессе. Правильное отношение к нему в управляемой среде не включает копание в последовательности фаз разрушения. Точка. S>>И чего он позволит достичь? Зачем, собственно, этот геморрой? PC>Потому что это самый правильный вариант, но в чистом виде он нигде не используется (ни в С++ ни CLS)
Еще раз: помимо теоретической правильности, есть какие-нибудь практические выгоды от его использования? Что, что-то станет более эффективно работать? Или удастся где-то сэкономить строчку кода? S>>Здравый смысл и огромный опыт. PC>Сомневаюсь...
А ты не сомневайся. Почитай блоги этих парней. Бокс и Хейльсберг совершенно точно были изготовлены не при помощи пальца. И почти все вопросы, которые могут в наши головы прийти, им тоже приходили. Но в отличие от нас, изредка пописывающих в форум философия в перерыве между обедом и кодингом, эти парни тратили по 8 часов в день именно на тщательное продумывание всех этих идей. А также на анализ кода существующих приложений на Java, С++, Delphi и VB. И на рассмотрение жалоб народа на недостатки этих языков и платформ. Да что там 8 часов в день — у них целые команды в подчинении, которые только этим и занимаются! Тут же такое дело — реализовать как раз очень несложно все. Особенно когда ты работаешь в МС. Захотел новое ключевое слово в C# — бах, и в следующем weekly build оно уже работает. Проблема в том, как придумать это все. Чтобы ничего ничему не противоречило, чтобы ни компилятор ни программист не глючили, и чтобы фича не внесла больше геморроя, чем ее отсутствие. S>>А, вот теперь мне все понятно. Я рекомендую тебе воздержаться от критики дотнета до тех пор, пока ты не получишь достаточный опыт. Нельзя слепо переносить опыт из одной среды в другую. GetType() настолько круче, чем typeid, что это даже обсуждать бессмысленно. На нем построено очень много чего в дотнете. PC>П. 5. Я ЭТО МЛИН ЗНАЮ! В скобках написано, что reflection не учитывается...
Да хоть п.8. Я не понимаю, как можно рассуждать о дотнете, отбрасывая Reflection. Ну давай отбросим от С++ перегрузку операторов, классы и исключения. Ну и в чем его мифическое преимущество перед C? Я как-то общался с дизайнером интерьеров. У них на эту тему есть мини-анекдот про заказчика, который хотел стену между комнатой и кухней, с одной стороны — прозрачную, а с другой — заклеенную обоями. Вот примерно также и ты — не против рефлекшна, но против GetType. Если ты вдруг имел в виду то, что можно было бы сделать GetType внешним по отношению к object, то я тебя разочарую — в контексте разговора внешний GetType работает точно так же, как и внутренний. Мы должны получать настоящий тип объекта. Нарушение этого правила приведет к очень большому геморрою.
S>>Но ты пока что не видишь всей этой мощи, потому как смотришь на дотнет сквозь танковую смотровую щель С++. PC>А ты уверен, что щель с моей стороны? Я нет.
Я — уверен. Потому что ты игнорируешь фичи дотнета, невозможные в плюсах. Эдак походя — типа "я в плюсах это имею парой строчек кода". Хрен там, не имеешь. Зато какие-то маловажные особенности реализации, отличающиеся от С++, ты считаешь достойными критики. PC>>>Очень жаль, что разрботчики .NET не читали Design & Evolution of C++ — много бы проблем избежали типа не совмещять понятия access и overload. S>>Уверяю тебя — читали. И изучили не только С++, а еще много языков. PC>И все в .NET замечательно да? фанатизм какой-то...
Ну, по крайней мере лучше, чем в большинстве предшествующих технологий.
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Pavel Chikulaev, Вы писали:
PC>Здравствуйте, Alxndr, Вы писали:
A>>Здравствуйте, Pavel Chikulaev, Вы писали:
A>>Ужос! PC>Для native типов в С++/CLI все остается по прежнему
PC>Там еще очень много подстав... Статью что-ли написать?
PC>Например:
... PC>Hidebysig in action.
Это ещё что. Как объяснить вот это:
using namespace System::IO;
int main() {
FileStream f = File::Create("test"); // error C3673: 'System::IO::FileStream' : class does not have a copy-constructor
FileStream f = FileStream("test", FileMode::Create); // error C3673
FileStream f("test", FileMode::Create); // OK
}
Что такое copy constructor для ref класса, зачем он в нужен, и какие реализации отличные от тривиальной у него могут быть?
Здравствуйте, Sinclair, Вы писали:
S>>>Есть. Просто ты их не замечаешь. Ты искусственно придумал пример, при котором финалайзер базового типа начинает заниматься фигней. PC>>Ок придумай искусственный пример где С++ с его семантикой смены динамического типа в дторе подведет. Жду. S>Как нефиг делать.
Извини, что так долго шел ответ...
S>
S>Я намеренно поскипал код конструкторов и методов Open для краткости. Поясню: наш класс реализует переоткрываемый ресурс. Его можно закрыть и переоткрыть вручную, а можно потерять в конструкторе. В данном варианте у нас Derived::Close() не будет вызван при разрушении Derived. Несмотря на то, что мы вызываем виртуальный метод из виртуального метода. Ок, допустим я в отчаянии прочел доку и узнал про эти грабли. Я дописываю деструктор ~Derived с вызовом Close. Отлично — теперь у меня дважды вызывается Base::Close().
1) RAII. Зачем open и close? Т.к. процесс создания, закрытия, открытия тоже самое, что и создание первого объкта, разрушение, создание второго. Зачем усложнять класс?
2) Т.к. ты сам придумал себе весь этот геморрой с open и close, то объект у тебя может иметь два состояния — есть ресурс и нет. Поэтому следует иметь или явную переменную обозначающую состояние (правильный способ), или неявную — так чтобы при повторном вызове close ничего не происходило:
PC>>Потому что это самый правильный вариант, но в чистом виде он нигде не используется (ни в С++ ни CLS) S>Еще раз: помимо теоретической правильности, есть какие-нибудь практические выгоды от его использования? Что, что-то станет более эффективно работать? Или удастся где-то сэкономить строчку кода?
S>>>Здравый смысл и огромный опыт. PC>>Сомневаюсь... S>А ты не сомневайся. Почитай блоги этих парней. Бокс и Хейльсберг совершенно точно были изготовлены не при помощи пальца. И почти все вопросы, которые могут в наши головы прийти, им тоже приходили. Но в отличие от нас, изредка пописывающих в форум философия в перерыве между обедом и кодингом, эти парни тратили по 8 часов в день именно на тщательное продумывание всех этих идей. А также на анализ кода существующих приложений на Java, С++, Delphi и VB. И на рассмотрение жалоб народа на недостатки этих языков и платформ. Да что там 8 часов в день — у них целые команды в подчинении, которые только этим и занимаются! Тут же такое дело — реализовать как раз очень несложно все. Особенно когда ты работаешь в МС. Захотел новое ключевое слово в C# — бах, и в следующем weekly build оно уже работает. Проблема в том, как придумать это все. Чтобы ничего ничему не противоречило, чтобы ни компилятор ни программист не глючили, и чтобы фича не внесла больше геморроя, чем ее отсутствие.
У разработчиков VB и Delphi тоже были целые комманды и что?
S>>>А, вот теперь мне все понятно. Я рекомендую тебе воздержаться от критики дотнета до тех пор, пока ты не получишь достаточный опыт. Нельзя слепо переносить опыт из одной среды в другую. GetType() настолько круче, чем typeid, что это даже обсуждать бессмысленно. На нем построено очень много чего в дотнете.
Тоже самое к тебе о С++.