Модераторы: Partizan, gambit

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Перегрузка функций как в Си++ или как в Джаве? 
V
    Опции темы
diadiavova
Дата 27.10.2008, 21:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доктор Зло(диагност, настоящий, с лицензией и полномочиями)
****


Профиль
Группа: Модератор
Сообщений: 5821
Регистрация: 14.8.2008
Где: В Коньфпольте

Репутация: 31
Всего: 142



Дело в том, что переопределённая виртуальная функция - это та же самая функция, для которой было изменено поведение. Не знаю как всё устроено в жабе(знаком обзорно), но в дотнете это может привести к неприятностям. Если функция помещена в класс просто для того, чтобы её могли использовать будущие поколения - то не страшно. Но если эта функция используется самим базовым классом, и влияет на его поведение, то её переопределение может привести к непредсказуемым последствиям. Поскольку программист не всегда знает детали реализации базового класса, то учесть все последствия переопрделния он не может. И понять источник проблем тоже. Когда метод затеняется он продолжает работать в классе и передаётся потомкам, просто к нему нет прямого доступа, но если он используется в базовом классе - он не будет лежать мёртвым грузом, а будет работать. В то же время метод с такой же сигнатурой может быть предоставлен для использования. Затенённый и затеняющий методы - два разных метода, имеющих одинаковую сигнатуру и находящихся в одной области видимости(в следствии чего один из них не виден). Переопределённый метод - это тот же самый метод, для которого в производном классе определен другой тип поведения.


--------------------
Хочешь получить мудрый совет - читай подписи участников форумов.
Злой доктор Щасзаболит smile
PM   Вверх
Dims
Дата 27.10.2008, 22:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1016
Регистрация: 21.11.2006

Репутация: 0
Всего: 11



Цитата(diadiavova @  27.10.2008,  21:43 Найти цитируемый пост)
Если функция помещена в класс просто для того, чтобы её могли использовать будущие поколения - то не страшно.


В Джаве функции переопределяются не для будущих поколений, а для полиморфизма, то есть, чтобы можно было работать с объектом не зная точно его типа. Для любого объекта, независимо от того, что нам в данный момент известно о его типе будет вызываться именно его метод. Это же логично.



Цитата(diadiavova @  27.10.2008,  21:43 Найти цитируемый пост)
Но если эта функция используется самим базовым классом, и влияет на его поведение, то её переопределение может привести к непредсказуемым последствиям.

Для этого есть слово final, которое запрещает переопределение функции. Если у нас такая функция, которая используется самим классом и вредно, чтобы она "знала правду" о классе, тогда мы делаем её final. Всё, теперь такого не случится. 

А в обратном случае это может даже помочь. Мы можем нарочно определить функцию, которая используется в базовом классе но в расчёте на возможное переопределение в наследниках. Тогда наследник сможет влиять на поведение вызывающей функцией базового класса.

А к каким последствиям, по-Вашему, может привести первый сценарий? Можете придумать пример?

Цитата(diadiavova @  27.10.2008,  21:43 Найти цитируемый пост)
Поскольку программист не всегда знает детали реализации базового класса, то учесть все последствия переопрделния он не может.


Мне кажется, это нелогично. Если человек не знает свойств базового класса, то зачем он взялся его переопределять? Пусть тогда напишет обёртку, а не наследника. 

Кроме того, если наследование чревато, то, значит, разработчик базового класса не позаботился о том, чтобы его класс можно было легко расширять.

Цитата(diadiavova @  27.10.2008,  21:43 Найти цитируемый пост)
Затенённый и затеняющий методы - два разных метода, имеющих одинаковую сигнатуру и находящихся в одной области видимости(в следствии чего один из них не виден).

Я это понимаю, всё-таки с Си++ знаком. Вопрос в том, нафига это нужно. Зачем нужен такой же метод, но делающий совершенно другое? По логике, метод должен быть спроектирован и назван так, чтобы было понятно его предназначение. Если у метода другое предназначение, то нужно его назвать по-другому. 

По Си++, повторяю, мне кажется, что причина была в экономии памяти. Всё-таки Си -- это макроассемблер, а Си++ это Си с классами. То есть, Си++ это ассемблер с классами. При программировании на Си++ можно (и желательно) представлять, что происходит с байтами, сколько занимает класс, как он расположен в памяти и так далее. А виртуальные функции вносят сумятицу в "ассемблерность". Поэтому для Си++ они лишь опция. А почему они лишь опция для C#?

PM MAIL   Вверх
diadiavova
Дата 27.10.2008, 23:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доктор Зло(диагност, настоящий, с лицензией и полномочиями)
****


Профиль
Группа: Модератор
Сообщений: 5821
Регистрация: 14.8.2008
Где: В Коньфпольте

Репутация: 31
Всего: 142



Цитата(Dims @  27.10.2008,  22:38 Найти цитируемый пост)
В Джаве функции переопределяются не для будущих поколений, а для полиморфизма, то есть, чтобы можно было работать с объектом не зная точно его типа. Для любого объекта, независимо от того, что нам в данный момент известно о его типе будет вызываться именно его метод. Это же логично.

В дотнете это всё тоже есть и такой подход даже является главенствующим, однако дополнительные возможности , насколько я понимаю "жрать не просят".
Когда я писал обудущих поколениях я имел в виду функции, которые не вызываются базовым классом, а предоставлены для использования производными. Относительно final, в до-диезе есть слово sealed которое(как я понимаю) деделает то же самое. Но если мне надо создать метод, переопределение которого будет иметь неблагоприяятные последствия из-за того, что в базовом классе этот метод вызывается в расчёте на определённое поведение и вдруг в производном классе это поведение изменяется. Чтобы этого избежать я просто не даю такой возможности и не делаю метод виртуальным. Что в этом плохого?
Если в жабе тоже есть такая возможность, то это говорит только о том, что различия здесь в том, какими функции считаются по умолчанию: в жабе - виртуальными, в дотнете - нет. И там и тут это можно изменить. Только в дотнете ещё можно и создать такую же функцию.
Насчёт упаковывания класса - хорошая задумка, особенно если в нём пара сотен членов и все надо упаковать, а в дотнете вместо этого надо упаковать всего-лишь один метод, к тому же затенённый метод можно вызвать из затеняющего(это не проблема).
Цитата(Dims @  27.10.2008,  22:38 Найти цитируемый пост)
А в обратном случае это может даже помочь. Мы можем нарочно определить функцию, которая используется в базовом классе но в расчёте на возможное переопределение в наследниках. Тогда наследник сможет влиять на поведение вызывающей функцией базового класса.

Ну для этого и есть виртуальные методы, в дотнете они тоже так работают(учитывая происхождение дотнета  вряд ли стоит этому удивляться).
Цитата(Dims @  27.10.2008,  22:38 Найти цитируемый пост)
А к каким последствиям, по-Вашему, может привести первый сценарий? Можете придумать пример?

Ну например такая ситуация:
Внутренний метод, вызывающий переопределённую функцию расчитывает на то, что значение ею возвращённое будет лежать в пределах определённого диапазона значений. Другое не предусмотренно из соображений экономии ресурсов. Переопределённый вариант функции(в отличии от первоначального) может возвращать значение, к которому вызывающий метод просто не готов.
Естественно это вызовет сбой. Конечно пример не очень показательный, но по крайней мере ясно, что я имею в виду.
Цитата(Dims @  27.10.2008,  22:38 Найти цитируемый пост)
Мне кажется, это нелогично. Если человек не знает свойств базового класса, то зачем он взялся его переопределять?

А от куда он может знать свойства? Если функция помечена как виртуальная - он знает, что её можно переопределить. Если нет - знает, что нельзя. Тут по-моему как раз всё просто.
Цитата(Dims @  27.10.2008,  22:38 Найти цитируемый пост)
Кроме того, если наследование чревато, то, значит, разработчик базового класса не позаботился о том, чтобы его класс можно было легко расширять.

Да нет. Как раз таки он позаботился, определив какие члены класса можно переопределять, а какие нет.
Цитата(Dims @  27.10.2008,  22:38 Найти цитируемый пост)
Я это понимаю, всё-таки с Си++ знаком. Вопрос в том, нафига это нужно. Зачем нужен такой же метод, но делающий совершенно другое? По логике, метод должен быть спроектирован и назван так, чтобы было понятно его предназначение. Если у метода другое предназначение, то нужно его назвать по-другому. 

Я не сказал, что он будет делать совершенно другое. Чуть-чуть другое, или просто по-другому, или например делая тоже самое(скажем посредством вызова затеняемого метода), при этом ещё инициировать какое-нибудь событие, да и вообще мало ли что ещё может понадобиться. Иногда бывает надо закрыть метод просто из-за того, что его вызов может не вписаться в логику класса и просто надо его перекрыть, например методом с пустой реализацией. И потом, в таком случае, почему не вызывает вопросов возможность перегрузки методов? Зачем нужно два метода с одинаковыми именами? 
Вариантов может быть много, хотя затенением я не пользуюсь, возможно именно по этому не могу привести какой-то яркий пример, но если так рассуждать "зачем нужно то, да зачем нужно это", то так можно очень далеко зайти. К примеру: зачем нужны модификаторы области видимости, когда можно просто не использовать те которые трогат нельзя, а зачем их прятать? Вопрос звучит странно, но он из того же набора, если мне не нужно, чтобы метод переопределяли - я не даю такой возможности
Цитата(Dims @  27.10.2008,  22:38 Найти цитируемый пост)
Поэтому для Си++ они лишь опция. А почему они лишь опция для C#?

Что значит "лишь опция"? Почему по-умолчанию они должны быть виртуальными? Потомучто в жабе так? Учитывая тот факт, что дотнет (мягко говоря) взял много из жабы, то наверно там это доставляло какие-то неудобства, раз уж это изменено. 


--------------------
Хочешь получить мудрый совет - читай подписи участников форумов.
Злой доктор Щасзаболит smile
PM   Вверх
Dims
Дата 28.10.2008, 00:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1016
Регистрация: 21.11.2006

Репутация: 0
Всего: 11



Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
Но если мне надо создать метод, переопределение которого будет иметь неблагоприяятные последствия из-за того, что в базовом классе этот метод вызывается в расчёте на определённое поведение и вдруг в производном классе это поведение изменяется. Чтобы этого избежать я просто не даю такой возможности и не делаю метод виртуальным. Что в этом плохого?


Я не знаю. Просто мне пока непонятно, зачем это может быть нужно и оно кажется нелогичным. 

Если брать двоих: потомка и предка, то, по логике, потомок всегда знает больше предка. Поэтому, бояться, что знающий больше что-то напортачит, нелогично. 

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

Но даже если возможности просто не нужны, то они "просят жрать" в том смысле, что требуют ресурсов, а взамен ничего не дают. Например, требуют от меня набирать слово "virtual".

Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
Если в жабе тоже есть такая возможность, то это говорит только о том, что различия здесь в том, какими функции считаются по умолчанию: в жабе - виртуальными, в дотнете - нет.

В том-то и дело, что в Джаве это нельзя изменить. Все функции всегда виртуальные. 



Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
Насчёт упаковывания класса - хорошая задумка, особенно если в нём пара сотен членов и все надо упаковать

Я так понимаю, что современные генераторы делают это автоматически. Мы же говорим о ситуации, когда разработчик не знает поведения базового класса и боится, что переопределение какой-то функции приведёт к нежелательным последствиям. Это значит, скорее всего, что ему и не нужны все 100 членов (раз он неосведомлён о том, что они делают).



Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
Внутренний метод, вызывающий переопределённую функцию расчитывает на то, что значение ею возвращённое будет лежать в пределах определённого диапазона значений. Другое не предусмотренно из соображений экономии ресурсов. Переопределённый вариант функции(в отличии от первоначального) может возвращать значение, к которому вызывающий метод просто не готов.

Всё же это абстрактная ситуация. Где конкретно такое может произойти? 

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

Например, функция "Рост" для "Животного" может возвращать значение от миллиметров до десятков метров. А та же функция для "Человека" примерно от метра до двух. 

Как может получиться так, что частный случай возвращает больший спектр значений, чем общий?

Если это происхожит, то это, наверное, не частный случай. В этом случае функцию просто, наверное, нужно назвать по-другому. 


Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
А от куда он может знать свойства? Если функция помечена как виртуальная - он знает, что её можно переопределить. Если нет - знает, что нельзя.

Ну это правильно, но если функция не помечена, как виртуальная, то её можно затенить. И зачем нужна эта возможность -- непонятно.


Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
Я не сказал, что он будет делать совершенно другое.


Ну а как же тогда? По логике ООП наследник -- это некто более осведомлённый. Частный случай предка. Его методы -- они либо повторяют методы предка, либо делают что-то более частное, детальное, что на уровне предка сделать было нельзя. Такая эволюция методов логична. 

Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
или например делая тоже самое(скажем посредством вызова затеняемого метода)

Ну а причём тут затенение? Виртуальная функция точно так же может вызвать перекрытый метод, разве нет? Для этого затенение не нужно.

Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
И потом, в таком случае, почему не вызывает вопросов возможность перегрузки методов? Зачем нужно два метода с одинаковыми именами? 

С одинаковыми именами, но с разными сигнатурами. Как правило, такие методы должны делать одно и тоже с разными исходными данными.

Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
Вариантов может быть много, хотя затенением я не пользуюсь

А как же? Объявляете все функции виртуальными? 

Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
но если так рассуждать "зачем нужно то, да зачем нужно это", то так можно очень далеко зайти

Ну я не знаю, куда можно зайти smile Я просто после Джавы и у меня возникают естественные вопросы. Джава намеренно очищена ото всех лишних вещей и, как показывает практика, это позволяет писать очень красиво-оопешно. 

Соответственно, когда какие-то вещи, которые были убраны и по которым ты совсем не скучал, возвращаются, неизбежно возникает вопрос, нафига. 

Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
К примеру: зачем нужны модификаторы области видимости

Это чё такое? public/private?

Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
когда можно просто не использовать те которые трогат нельзя, а зачем их прятат

Минуточку, но это ведь как раз Вы говорите, что что плохого в затенении, если его можно просто не использовать. 

Повторюсь, что слово override мне нравится. Оно добавляет проверку (кстати, если они любители проверок, то нафига убрали throws? в джаве есть два типа Exception, одни из них обязательно описывать в сигнатуре метода при помощи слова throws; то есть, ты смотришь на метод и видишь, чего он выбрасывает)

Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
Вопрос звучит странно, но он из того же набора, если мне не нужно, чтобы метод переопределяли - я не даю такой возможности

Как Вы можете не дать затенять?

Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
Почему по-умолчанию они должны быть виртуальными?

Ну если это единственная полезная их форма, то разве это не основание?

Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
Учитывая тот факт, что дотнет (мягко говоря) взял много из жабы, то наверно там это доставляло какие-то неудобства, раз уж это изменено.  

Ну так давайте выясним, какие. Разве это не интересно?
PM MAIL   Вверх
diadiavova
Дата 28.10.2008, 02:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доктор Зло(диагност, настоящий, с лицензией и полномочиями)
****


Профиль
Группа: Модератор
Сообщений: 5821
Регистрация: 14.8.2008
Где: В Коньфпольте

Репутация: 31
Всего: 142



Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Если брать двоих: потомка и предка, то, по логике, потомок всегда знает больше предка. Поэтому, бояться, что знающий больше что-то напортачит, нелогично. 

Потомок может и знает, только код этого потомка пишет программист, который знает не всё.

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Кроме того, затенение само по себе чревато ошибками: если мы приведём наследника к типу предка, что совершенно допустимо и не должно приводить ни к каким плохим последствиям, и вызовем метод, то вызовется затенённый метод. То есть, метод предка отработает на материале наследника, что чревато гораздо более серьёзными глюками, так как предок в принципе не может ничего знать о наследнике.

Наследник должен создаваться с учётом поведения предка. Предок же не может заранее знать, что прийдёт в голову программисту который будет реализовывать наследование, поэтому логично некоторые действия просто запретить. Но запрещать создавать методы с определённой сигнатурой не стали, дабы расширить возможности. Ну к затеняющему методу можно относиться как к перегруженному. Перегруженные методы - это тоже разные методы, а одно имя им даётся намеренно, именно потому, что они делают одно дело но по-разному.

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Но даже если возможности просто не нужны, то они "просят жрать" в том смысле, что требуют ресурсов, а взамен ничего не дают. Например, требуют от меня набирать слово "virtual".

Ну если не набирать это слово, тогда компилятору будет не понятно почему программист создал метод с существующим именем: по-ошибке или намеренно. Полиморфизм - это хорошо, а если я просто создаю метод для поддержки какой-то функциональности и мне не надо, чтобы его переопределяли. Ядолжен каждый раз об этом уведомлять словом final? По моему гораздо проще реализовать метод без учёта того, что он может быть переопределён. Я например виртуальные методы создаю как раз в тех случаях, когда именно на то и расчитываю, что потом можно будет переопределить их, но там продумывается логика и все возможные нюансы возможной(!) реализации в производном классе. Гораздо проще написать метод под конкретные задачи, да и ресурсов он меньше жрёт, потомучто не проверяет тех возможностей, которых не должно быть в случае, если всё пойдёт как я задумал. В виртуальном методе всё это надо учитывать.

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
В том-то и дело, что в Джаве это нельзя изменить. Все функции всегда виртуальные. 

Тогда я не понял, что такое final.
Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Я так понимаю, что современные генераторы делают это автоматически. Мы же говорим о ситуации, когда разработчик не знает поведения базового класса и боится, что переопределение какой-то функции приведёт к нежелательным последствиям. Это значит, скорее всего, что ему и не нужны все 100 членов (раз он неосведомлён о том, что они делают).

Ему не члены нужны а сам класс. Возможно он вообще должен быть определённого типа там где используется. Базовый класс вообще может быть абстрактным, а реализуется только потому, что какой-то метод затребовал в качестве параметра экземпляр класса производного от данного, да вариантов море. Надо мне конрол создать, не знаю всех нюансов поведения, сделаю упаковку , и куда я с ней? В коллекцию Controls её не добавишь, что мне эту упаковку сбоку пристраивать чтоли, а если некоторые методы надо переопределить, как это реализовать с упаковкой? Да и потом мне не ясна такая логика, когда написать virtual трудно, а  создавать упаковку, даже если генерить код автоматом - легко.

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Как может получиться так, что частный случай возвращает больший спектр значений, чем общий?

Если оба класса пишет один человек - такого быть не должно. Но это не всегда так.
Насчёт специфичности класса я не согласен. Потомок расширяет базовый класс(кстати в jscript.net для указания базового класса используется слово exteds). Если считать, что производный класс сужает возможности(как в примере с ростом) тогда самым богатым классом должен быть Object, а все остальные более специфичными, ну это же не так.

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Если это происхожит, то это, наверное, не частный случай. В этом случае функцию просто, наверное, нужно назвать по-другому. 

Это точно не частный случай. А функцию можно назвать и по-другому, но можно и так же(если надо).
Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Ну это правильно, но если функция не помечена, как виртуальная, то её можно затенить. И зачем нужна эта возможность -- непонятно.

Возможность эта нужна за тем же зачем и переопределить. Если нужно, чтобы в производном классе была такая функция, но выполняла другие действия, то эту функцию создают. Если функция виртуальная, то эту новую функцию можно оформить как переопределяющую(не обязательно виртуальные функции тоже можно затенять), а в остальных случаях она будет затенять соответствующую функцию базового класса. Я подчёркиваю: в обоих случаях делается одно и то же. Разница состоит в том, что при переопределении все вызовы, определённые в базовом классе, будут обращаться к новой версии функции, а при затенении - к старой. Но новая реализация функции имеет место в обоих случаях.

То есть: возможность затенения нужна для того, чтобы при создании такого же метода в производном классе, поведение базового, завязанное на ней не менялось.


Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Ну а как же тогда? По логике ООП наследник -- это некто более осведомлённый. Частный случай предка. Его методы -- они либо повторяют методы предка, либо делают что-то более частное, детальное, что на уровне предка сделать было нельзя. Такая эволюция методов логична. 


Я бы сказал не что-то более частное, а скорее, что-то сходное по логике, но иногда совсем другое. Что-то, что может быть тем же, что и в базовом классе, только применительно к другому контексту.


Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Ну а причём тут затенение? Виртуальная функция точно так же может вызвать перекрытый метод, разве нет? Для этого затенение не нужно.

Может, только как  я уже сказал, базовый класс тоже будет её вызывать. А пример я привёл для того, чтобы показать, что метод не только не делает что-то другое, аможет вести себя так же  как виртуальный, даже вызывать затеняемый метод, другой вопрос, что его не будет вызывать базовый класс.

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
С одинаковыми именами, но с разными сигнатурами. Как правило, такие методы должны делать одно и тоже с разными исходными данными.

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


Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
А как же? Объявляете все функции виртуальными? 

Нет, только те, которые собираюсь переопределять. Вся фишка в том, что как правило в затенении нет необходимости, но если она возникает, то у меня есть возможность создать в производном классе функцию с нужной сигнатурой, не затрагивая болевых точек базового класса. И хорошо, что она есть.
Я понимаю, что без этого, наверно можно обойтись, но это удобно. Если переопределение функции опасно - я лишён такой возможности. Разве это плохо? Сколько косяков можно напороть просто из-за незнания всех возможных опасностей. В современных языках в основном приходится работать с огромным количеством библиотечных классов, знать все нюансы поведения которых, просто невозможно. И если там есть ограничения, то это приводит просто к тому, что я не могу сделать некоторых вредных штук.
Взять например зоопарк. Звери сидят в клетках, чтоб никого не растерзали, но на расстоянии от клетки стоит ограда для людей, чтобы они не подходили близко. Ограничение свободы? Да. Хорошо это или плохо в данном случае?

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Ну я не знаю, куда можно зайти smile Я просто после Джавы и у меня возникают естественные вопросы. Джава намеренно очищена ото всех лишних вещей и, как показывает практика, это позволяет писать очень красиво-оопешно. 

Соответственно, когда какие-то вещи, которые были убраны и по которым ты совсем не скучал, возвращаются, неизбежно возникает вопрос, нафига. 

Ну может от этого она не очищена, просто там до этогоне додумались? smile 
А если учесть, что у дотнета ноги из жабы растут...
Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Это чё такое? public/private?

Угу
===========
Насчёт trows я не понял, но в дотнетовских языках это тоже есть, не знаю, может в жабе есть варианты...

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Как Вы можете не дать затенять?

А зачем? Не давать переопределять нужно для того, чтобы вызовы базового класса не получали подмену, а зачем не давать затенять? Затенение - другой метод. Пусть создают сколько влезет методов(или других членов) с такими же сигнатурами, на поведение, определённое в базовом классе это не повлияет. Запрещать затенение - это всё равно, что запрещать создавать члены с определёнными именами. Это ничего не даст. А вот запрет на изменение логики на какю-то неожиданную, может оказаться полезным.

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
Почему по-умолчанию они должны быть виртуальными?

Ну если это единственная полезная их форма, то разве это не основание?

Эта форма не единственная полезная, и кроме того - потенциально опасная.


Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Ну так давайте выясним, какие. Разве это не интересно? 

Да в общем-то этим и занимаемся уже несколько дней. smile

Добавлено через 10 минут и 18 секунд
Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Если брать двоих: потомка и предка, то, по логике, потомок всегда знает больше предка. Поэтому, бояться, что знающий больше что-то напортачит, нелогично. 

Потомок может и знает, только код этого потомка пишет программист, который знает не всё.

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Кроме того, затенение само по себе чревато ошибками: если мы приведём наследника к типу предка, что совершенно допустимо и не должно приводить ни к каким плохим последствиям, и вызовем метод, то вызовется затенённый метод. То есть, метод предка отработает на материале наследника, что чревато гораздо более серьёзными глюками, так как предок в принципе не может ничего знать о наследнике.

Наследник должен создаваться с учётом поведения предка. Предок же не может заранее знать, что прийдёт в голову программисту который будет реализовывать наследование, поэтому логично некоторые действия просто запретить. Но запрещать создавать методы с определённой сигнатурой не стали, дабы расширить возможности. Ну к затеняющему методу можно относиться как к перегруженному. Перегруженные методы - это тоже разные методы, а одно имя им даётся намеренно, именно потому, что они делают одно дело но по-разному.

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Но даже если возможности просто не нужны, то они "просят жрать" в том смысле, что требуют ресурсов, а взамен ничего не дают. Например, требуют от меня набирать слово "virtual".

Ну если не набирать это слово, тогда компилятору будет не понятно почему программист создал метод с существующим именем: по-ошибке или намеренно. Полиморфизм - это хорошо, а если я просто создаю метод для поддержки какой-то функциональности и мне не надо, чтобы его переопределяли. Ядолжен каждый раз об этом уведомлять словом final? По моему гораздо проще реализовать метод без учёта того, что он может быть переопределён. Я например виртуальные методы создаю как раз в тех случаях, когда именно на то и расчитываю, что потом можно будет переопределить их, но там продумывается логика и все возможные нюансы возможной(!) реализации в производном классе. Гораздо проще написать метод под конкретные задачи, да и ресурсов он меньше жрёт, потомучто не проверяет тех возможностей, которых не должно быть в случае, если всё пойдёт как я задумал. В виртуальном методе всё это надо учитывать.

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
В том-то и дело, что в Джаве это нельзя изменить. Все функции всегда виртуальные. 

Тогда я не понял, что такое final.
Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Я так понимаю, что современные генераторы делают это автоматически. Мы же говорим о ситуации, когда разработчик не знает поведения базового класса и боится, что переопределение какой-то функции приведёт к нежелательным последствиям. Это значит, скорее всего, что ему и не нужны все 100 членов (раз он неосведомлён о том, что они делают).

Ему не члены нужны а сам класс. Возможно он вообще должен быть определённого типа там где используется. Базовый класс вообще может быть абстрактным, а реализуется только потому, что какой-то метод затребовал в качестве параметра экземпляр класса производного от данного, да вариантов море. Надо мне конрол создать, не знаю всех нюансов поведения, сделаю упаковку , и куда я с ней? В коллекцию Controls её не добавишь, что мне эту упаковку сбоку пристраивать чтоли, а если некоторые методы надо переопределить, как это реализовать с упаковкой? Да и потом мне не ясна такая логика, когда написать virtual трудно, а  создавать упаковку, даже если генерить код автоматом - легко.

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Как может получиться так, что частный случай возвращает больший спектр значений, чем общий?

Если оба класса пишет один человек - такого быть не должно. Но это не всегда так.
Насчёт специфичности класса я не согласен. Потомок расширяет базовый класс(кстати в jscript.net для указания базового класса используется слово exteds). Если считать, что производный класс сужает возможности(как в примере с ростом) тогда самым богатым классом должен быть Object, а все остальные более специфичными, ну это же не так.

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Если это происхожит, то это, наверное, не частный случай. В этом случае функцию просто, наверное, нужно назвать по-другому. 

Это точно не частный случай. А функцию можно назвать и по-другому, но можно и так же(если надо).
Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Ну это правильно, но если функция не помечена, как виртуальная, то её можно затенить. И зачем нужна эта возможность -- непонятно.

Возможность эта нужна за тем же зачем и переопределить. Если нужно, чтобы в производном классе была такая функция, но выполняла другие действия, то эту функцию создают. Если функция виртуальная, то эту новую функцию можно оформить как переопределяющую(не обязательно виртуальные функции тоже можно затенять), а в остальных случаях она будет затенять соответствующую функцию базового класса. Я подчёркиваю: в обоих случаях делается одно и то же. Разница состоит в том, что при переопределении все вызовы, определённые в базовом классе, будут обращаться к новой версии функции, а при затенении - к старой. Но новая реализация функции имеет место в обоих случаях.

То есть: возможность затенения нужна для того, чтобы при создании такого же метода в производном классе, поведение базового, завязанное на ней не менялось.


Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Ну а как же тогда? По логике ООП наследник -- это некто более осведомлённый. Частный случай предка. Его методы -- они либо повторяют методы предка, либо делают что-то более частное, детальное, что на уровне предка сделать было нельзя. Такая эволюция методов логична. 


Я бы сказал не что-то более частное, а скорее, что-то сходное по логике, но иногда совсем другое. Что-то, что может быть тем же, что и в базовом классе, только применительно к другому контексту.


Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Ну а причём тут затенение? Виртуальная функция точно так же может вызвать перекрытый метод, разве нет? Для этого затенение не нужно.

Может, только как  я уже сказал, базовый класс тоже будет её вызывать. А пример я привёл для того, чтобы показать, что метод не только не делает что-то другое, аможет вести себя так же  как виртуальный, даже вызывать затеняемый метод, другой вопрос, что его не будет вызывать базовый класс.

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
С одинаковыми именами, но с разными сигнатурами. Как правило, такие методы должны делать одно и тоже с разными исходными данными.

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


Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
А как же? Объявляете все функции виртуальными? 

Нет, только те, которые собираюсь переопределять. Вся фишка в том, что как правило в затенении нет необходимости, но если она возникает, то у меня есть возможность создать в производном классе функцию с нужной сигнатурой, не затрагивая болевых точек базового класса. И хорошо, что она есть.
Я понимаю, что без этого, наверно можно обойтись, но это удобно. Если переопределение функции опасно - я лишён такой возможности. Разве это плохо? Сколько косяков можно напороть просто из-за незнания всех возможных опасностей. В современных языках в основном приходится работать с огромным количеством библиотечных классов, знать все нюансы поведения которых, просто невозможно. И если там есть ограничения, то это приводит просто к тому, что я не могу сделать некоторых вредных штук.
Взять например зоопарк. Звери сидят в клетках, чтоб никого не растерзали, но на расстоянии от клетки стоит ограда для людей, чтобы они не подходили близко. Ограничение свободы? Да. Хорошо это или плохо в данном случае?

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Ну я не знаю, куда можно зайти smile Я просто после Джавы и у меня возникают естественные вопросы. Джава намеренно очищена ото всех лишних вещей и, как показывает практика, это позволяет писать очень красиво-оопешно. 

Соответственно, когда какие-то вещи, которые были убраны и по которым ты совсем не скучал, возвращаются, неизбежно возникает вопрос, нафига. 

Ну может от этого она не очищена, просто там до этогоне додумались? smile 
А если учесть, что у дотнета ноги из жабы растут...
Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Это чё такое? public/private?

Угу
===========
Насчёт trows я не понял, но в дотнетовских языках это тоже есть, не знаю, может в жабе есть варианты...

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Как Вы можете не дать затенять?

А зачем? Не давать переопределять нужно для того, чтобы вызовы базового класса не получали подмену, а зачем не давать затенять? Затенение - другой метод. Пусть создают сколько влезет методов(или других членов) с такими же сигнатурами, на поведение, определённое в базовом классе это не повлияет. Запрещать затенение - это всё равно, что запрещать создавать члены с определёнными именами. Это ничего не даст. А вот запрет на изменение логики на какю-то неожиданную, может оказаться полезным.

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Цитата(diadiavova @  27.10.2008,  23:39 Найти цитируемый пост)
Почему по-умолчанию они должны быть виртуальными?

Ну если это единственная полезная их форма, то разве это не основание?

Эта форма не единственная полезная, и кроме того - потенциально опасная.


Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Ну так давайте выясним, какие. Разве это не интересно? 

Да в общем-то этим и занимаемся уже несколько дней. smile 


--------------------
Хочешь получить мудрый совет - читай подписи участников форумов.
Злой доктор Щасзаболит smile
PM   Вверх
PashaPash
Дата 28.10.2008, 10:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



Dims
Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Я не знаю. Просто мне пока непонятно, зачем это может быть нужно и оно кажется нелогичным. 

Если брать двоих: потомка и предка, то, по логике, потомок всегда знает больше предка. Поэтому, бояться, что знающий больше что-то напортачит, нелогично....

По логике потомок не знает больше предка, скорее к ним применимо "потомок есть предок". Человек, пишущий класс-предок, знает его public/protected интерфейс и внутреннюю реализацию. Человек, пишущий класс-потомок, знает о предке только public/protected интерфейс и ничего не знает о реализации. И, соответственно, не должен никак на эту реализацию влиять, если это явно не разрешил автор предка. Значения по умолчанию направлены на уменьшение интерфейса класса/сборки - private/internal вместо public, невиртуальные вместо virtual. Вообще, с точки зрения ООД наследование настолько увеличивает связность и тянет за собой столько ошибок, что надо классы по умолчанию sealed объявлять.

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Кроме того, затенение само по себе чревато ошибками: если мы приведём наследника к типу предка, что совершенно допустимо и не должно приводить ни к каким плохим последствиям, и вызовем метод, то вызовется затенённый метод. То есть, метод предка отработает на материале наследника, что чревато гораздо более серьёзными глюками, так как предок в принципе не может ничего знать о наследнике.

Вот именно поэтому и выводится warning, и требуется необязательное слово new. Просто надо воспринимать warnings as errors smile

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
Но даже если возможности просто не нужны, то они "просят жрать" в том смысле, что требуют ресурсов, а взамен ничего не дают. Например, требуют от меня набирать слово "virtual".

Набирая слово virtual, ты явно увеличиваешь площадь интерфейса. Во время набора нужно подумать что будет, если потомок реализует этот метод по-своему. Учесть что у автора потомка не будет знаний о внутреннем устройстве твоего класса. Учесть что через год какой-нибудь нуб придет и переопределит этот метод через 4 класса в цепочке наследования, при этом все 4 будут написаны тобой и будут завязаны на внутренее устройство родителя. Возможные проблемы гораздо круче чем проблемы при игнорировании варнинга "нужен new". Поэтому и слово длиннее на 4 буквы, чтобы больше времени было smile

Цитата(Dims @  28.10.2008,  00:34 Найти цитируемый пост)
нафига убрали throws

Затем, что классы-потомки могут бросать исключения, не описанные в синатуре предков. И еще затем, чтобы уменьшить связность и проблемы с версиями. В .net можно подменить, например, сборку с базовым классом даже если сборка потомка явно привязана к ее версии. И в момент выполнения список throws оказался бы совсем не таким, как в момент компиляции. В java фишек с версиями нет, там throws проверяется только в compile time.

Это сообщение отредактировал(а) PashaPash - 28.10.2008, 10:46


--------------------
PM MAIL WWW   Вверх
Dims
Дата 28.10.2008, 11:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1016
Регистрация: 21.11.2006

Репутация: 0
Всего: 11



Цитата(diadiavova @  28.10.2008,  02:20 Найти цитируемый пост)
Ну может от этого она не очищена, просто там до этогоне додумались? smile 

Это было в Си++, потом это убрали в Джаве, а потом обратно вернули в C#.

Джава произошла от Си++, а C# от них обоих. 

Цитата(diadiavova @  28.10.2008,  02:20 Найти цитируемый пост)
А зачем? Не давать переопределять нужно для того, чтобы вызовы базового класса не получали подмену, а зачем не давать затенять?

Я не знаю. Я не знаю ни зачем не давать затенять, ни зачем давать. В Си++ я понимаю, зачем сделано затенение, а зачем в C# не понимаю.

Добавлено через 8 минут и 30 секунд
Цитата(PashaPash @  28.10.2008,  10:44 Найти цитируемый пост)
Человек, пишущий класс-потомок, знает о предке только public/protected интерфейс и ничего не знает о реализации.

Правильно. Но если ему в инструкции сказано, что переопределив такой-то метод он добьётся такого-то результата, то он кое-что знает и о реализации. 

Цитата(PashaPash @  28.10.2008,  10:44 Найти цитируемый пост)
Затем, что классы-потомки могут бросать исключения, не описанные в синатуре предков.

Ну давайте тогда уберём спецификацию возвращаемого типа, чтобы потомки могли и возвращать объекты другого типа. 

Ну ладно, это отклонение.

В этой теме давайте разберёмся, зачем нужно затенение.


PM MAIL   Вверх
PashaPash
Дата 28.10.2008, 13:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



Цитата(Dims @  28.10.2008,  11:48 Найти цитируемый пост)
Правильно. Но если ему в инструкции сказано, что переопределив такой-то метод он добьётся такого-то результата, то он кое-что знает и о реализации. 

Основной принцип ооп - о классе известен только его внешний интерфейс. Если в интрукции сказано что переопределение метода как-то повлияет на результат, то это значит все то же - что метод - часть public интерфейса класса. И никак не значит, что наследник что-то узнает о реализации. Если для наследования нужно нарушить инкапсуляцию, то это какое-то не ооп-ное наследование. На самом деле вопрос примерно на уровне:
А почему методы не public по умолчанию? в языке xxx все методы pubic, очень удобно. Ну и что, что программер может не знать зачем они нужны. Никто ж не заставляет его их вызвать, да и автору базового класса легче - не надо писать дурацкие public. Да, в .net/java есть возможность сделать метод public, но зачем нужны private методы, это ж неудобно.

Цитата(Dims @  28.10.2008,  11:48 Найти цитируемый пост)
Ну давайте тогда уберём спецификацию возвращаемого типа, чтобы потомки могли и возвращать объекты другого типа. 

в jave бросаемые исключения - часть интерфейса, т.е. подразумевается что они могут возникать при обычном ходе выполнения программы. В .net исключения - это именно исключительные ситуации, и они не являются частью интерфейса. На самом деле код очень редко может нормально обработать исключение, и принудительное перечисление типов приведет к желанию программеров тупо исключения глушить. И код очень редко знает полный список исключений, которые может бросить вызываемый им кусок. Кроме кода на границе слоев, ес-но

Цитата(Dims @  28.10.2008,  11:48 Найти цитируемый пост)
Это было в Си++, потом это убрали в Джаве, а потом обратно вернули в C#.
Джава произошла от Си++, а C# от них обоих. 

С таким же успехом можно утверждать что C# произошел от Eiffel или от Modula. C#/.NET - не наследник java, это самостоятельная платформа. Ничего в нем не "убирали" и не "добавляли". В нем все так и было с самого начала. И вопросы с позиции "почему тут не так, как в java" имеют общий ответ: потому что это не java, не java от MS, и не наследник Java. И потому что в java тоже есть просчеты с точки зрения дизайна платформы - хотя бы дурацкое выделение элементарных типов, обязательное перечисление исключений, проблемы с версионностью, вирутальные по умолчанию... C# не обязан копировать из java ее проблемы.


--------------------
PM MAIL WWW   Вверх
diadiavova
Дата 28.10.2008, 14:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доктор Зло(диагност, настоящий, с лицензией и полномочиями)
****


Профиль
Группа: Модератор
Сообщений: 5821
Регистрация: 14.8.2008
Где: В Коньфпольте

Репутация: 31
Всего: 142



Цитата(Dims @  28.10.2008,  11:48 Найти цитируемый пост)
Правильно. Но если ему в инструкции сказано, что переопределив такой-то метод он добьётся такого-то результата, то он кое-что знает и о реализации. 

А зачем такие сложности, когда можно просто запретить и всё(как в зоопарке)

Цитата(Dims @  28.10.2008,  11:48 Найти цитируемый пост)
В этой теме давайте разберёмся, зачем нужно затенение.

Проблема именно в том, что в этой теме мы смешали в кучу несколько близких тем. Это вносит некоторый сумбур.
1.Почему не все методы виртуальные?
Насколько я понял в жабе либо все методы виртуальны, либо класс вообще не наследуется. В дотнете, в противовес этому, механизм наследования можно настроить тонко. То есть при написании класса автор сам определяет что можно переопределить, а что надо оставить без изменений. На мой взгляд - дотнетовский подход более гибкий, чем "всё или ничего".

2. Зачем нужно затенение?
В общем то это следует из первого вопроса. Если возникает ситуация, в которой необходима собственная реализация метода, а он не виртуальный, то существует возможность это реализовать не затрагивая функций базового класса, завязанных на реализации данного метода в базовом классе.

3. Почему методы не виртуальны по-умолчанию?
Реализация функциональности завязанная на виртуальных методах требует учёта того, что они могут быть переопределены. Реализовать функциональность под конкретные задачи - проще и экономичнее, чем проверять все возможные(и невозможные) последствия переопределения.

ЗЫ

PashaPash, нам скоро с гастролями можно будет выступать.
Как Терренс и Филипп. smile 


--------------------
Хочешь получить мудрый совет - читай подписи участников форумов.
Злой доктор Щасзаболит smile
PM   Вверх
Dims
Дата 3.11.2008, 12:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1016
Регистрация: 21.11.2006

Репутация: 0
Всего: 11



Цитата(PashaPash @  28.10.2008,  13:48 Найти цитируемый пост)
Основной принцип ооп - о классе известен только его внешний интерфейс.

А что значит "известен" внешний интерфейс? Ведь это же не означает просто, что известны имена методов и типы их параметров. Это означает, что известно, и что эти методы ДЕЛАЮТ. Например, метод "длина" класса "вектор" вычисляет длину вектора. 

Цитата(PashaPash @  28.10.2008,  13:48 Найти цитируемый пост)
На самом деле вопрос примерно на уровне:

Нет, вопрос совсем на другом уровне.

Цитата(PashaPash @  28.10.2008,  13:48 Найти цитируемый пост)
Ничего в нем не "убирали" и не "добавляли". В нем все так и было с самого начала. И вопросы с позиции "почему тут не так, как в java" имеют общий ответ: потому что это не java, не java от MS, и не наследник Java

То есть, Вы утверждаете, что разработчики C# не продумывали свойства языка, а просто сделали не так как в Java?

Цитата(PashaPash @  28.10.2008,  13:48 Найти цитируемый пост)
хотя бы дурацкое выделение элементарных типов, обязательное перечисление исключений, проблемы с версионностью, вирутальные по умолчанию

Однако, эти вещи были специально созданы разработчиками, имея в виду какие-то мысли. Может быть, мысли и ошибочные, но они были. А в Вашем описании C# это вещь в себе, которая не произошла ни от кого и функции которой просто есть, нипочему.

Я совершенно с этим не согласен. Я думаю, что и тут были какие-то мысли, просто мы их не знаем. Почему просто в этом не признаться?

Добавлено через 51 секунду
Цитата(diadiavova @  28.10.2008,  14:13 Найти цитируемый пост)
А зачем такие сложности, когда можно просто запретить и всё(как в зоопарке)

Мы разбираем не вопрос как запретить, а вопрос как разрешить. И зачем.

Добавлено через 4 минуты и 49 секунд
На самом деле, я понял, что такое затенение функций -- это отколовшаяся часть системы преобразования типов.

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

В этом случае у каждого объекта должна работать своя функция, то есть, все функции должны быть виртуальными.

Во втором случае программист может хотеть принудительно превратить наследника в предка, обрубить ему все особенности. 

В этом случае методы должны браться от предка.
PM MAIL   Вверх
diadiavova
Дата 3.11.2008, 12:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доктор Зло(диагност, настоящий, с лицензией и полномочиями)
****


Профиль
Группа: Модератор
Сообщений: 5821
Регистрация: 14.8.2008
Где: В Коньфпольте

Репутация: 31
Всего: 142



Цитата(Dims @  3.11.2008,  12:28 Найти цитируемый пост)
Мы разбираем не вопрос как запретить, а вопрос как разрешить. И зачем.

Честно говоря: не понимаю, как одно можно рассматривать вне контекста другого. Я говорил всего лишь о том, что ппроще запретить переопределение конкретных членов, чем описывать в документации какие члены переопределять не следует.

Цитата(Dims @  3.11.2008,  12:28 Найти цитируемый пост)
Возможны как минимум два преобразования типов от типа наследника к типу предка. При первом преобразовании отражается ситуация, когда программисту просто неважен конкретный тип наследника. В этом случае он хочет работать с наследником, думая о предке, но при этом чтобы ничего не нарушалось. 

Конкретный тип не важен тогда, когда в базовом классе либо вообще отсутствуют виртуальные члены, либо те, что есть не переопределены в производном. В этом случае при преобразовании к базовому типу объект ведёт себя так как будто это экземпляр базового типа без каких-либо изменений.
Здесь же мы имеем дело с ситуацией, когда переопределёнными могут быть некоторые члены, а остальные - нет. Поведение такого объекта будет отличаться от экземпляров других классов, так же произведённых от данного, в силу того, что в нём таки будут присутствовать виртуальные члены.



--------------------
Хочешь получить мудрый совет - читай подписи участников форумов.
Злой доктор Щасзаболит smile
PM   Вверх
Dims
Дата 3.11.2008, 13:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1016
Регистрация: 21.11.2006

Репутация: 0
Всего: 11



Цитата(diadiavova @  3.11.2008,  12:52 Найти цитируемый пост)
Честно говоря: не понимаю, как одно можно рассматривать вне контекста другого. Я говорил всего лишь о том, что ппроще запретить переопределение конкретных членов, чем описывать в документации какие члены переопределять не следует.


Ну Вы же сами предложили рассмотреть случай -- а вдруг человек переопределит метод и это приведёт к ужасным последствиям. И я полностью с Вами согласен: проще запретить. Это можно сделать и в Джаве при помощи final.

А вот когда это не запрещено, как я понимаю, по Вашей теории, и могут быть проблемы. 

Вопрос: какие?

Цитата(diadiavova @  3.11.2008,  12:52 Найти цитируемый пост)
Здесь же мы имеем дело с ситуацией, когда переопределёнными могут быть некоторые члены, а остальные - нет. Поведение такого объекта будет отличаться от экземпляров других классов, так же произведённых от данного, в силу того, что в нём таки будут присутствовать виртуальные члены.

Хочу подчеркнуть, что тут я рассматриваю ситуацию гипотетического языка. Я слышал, что в новом Си++ ввели несколько разновидностей преобразования типов, но ещё не разбирался с ними и не уверен, что это то.

Так вот, в этом гипотетическом языке все функции виртуальные, как и в Джаве. А вопрос, какую из них использовать, решается в зависимости от формы преобразования типа.

По моим представлениям, после того, как над объектом было проведено "преобразовние к предку первого рода", он не перестал быть потомком. Поэтому, все функции по отношению к нему будут браться от потомка, если они там переопределены.

Если к объекту применено преобразование типа "второго рода", то он полностью превращён в предка, а лишняя информация, включая переопределённые функции, стирается. 
PM MAIL   Вверх
diadiavova
Дата 3.11.2008, 13:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доктор Зло(диагност, настоящий, с лицензией и полномочиями)
****


Профиль
Группа: Модератор
Сообщений: 5821
Регистрация: 14.8.2008
Где: В Коньфпольте

Репутация: 31
Всего: 142



Цитата(Dims @  3.11.2008,  13:16 Найти цитируемый пост)
Это можно сделать и в Джаве при помощи final.

Просто тут есть выбор: запрещать всё или только часть. В дотнетовских языках тоже есть возможность запретить дальнейшее наследование класса. Кроме того, здесь есть возможность указать, что в дальнейшем виртуальный член перестаёт быть виртуальным(то есть больше не переопределяется в производных классах). Здесь есть возможность затенения виртуальных членов(выбор между переопределением и затенением). То есть здесь можно всё то же, что и в яве, плюс дополнительные возможности.

Цитата(Dims @  3.11.2008,  13:16 Найти цитируемый пост)
А вот когда это не запрещено, как я понимаю, по Вашей теории, и могут быть проблемы. 

Вопрос: какие?

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

Цитата(Dims @  3.11.2008,  13:16 Найти цитируемый пост)
Хочу подчеркнуть, что тут я рассматриваю ситуацию гипотетического языка. Я слышал, что в новом Си++ ввели несколько разновидностей преобразования типов, но ещё не разбирался с ними и не уверен, что это то.

Так вот, в этом гипотетическом языке все функции виртуальные, как и в Джаве. А вопрос, какую из них использовать, решается в зависимости от формы преобразования типа.

По моим представлениям, после того, как над объектом было проведено "преобразовние к предку первого рода", он не перестал быть потомком. Поэтому, все функции по отношению к нему будут браться от потомка, если они там переопределены.

Если к объекту применено преобразование типа "второго рода", то он полностью превращён в предка, а лишняя информация, включая переопределённые функции, стирается.  


Трудно рассуждать о гипотетическом языке, но в такую модель изначально заложены грабли. Вместо тонкой настройки поведения конкретного класса (в том числе в случае приведения типов), использовать общие правила для всех типов, которые в конкретном случае нельзя изменить...
Не думаю, что это наилучшее решение.
При желании поведение класса при приведении типов и так можно задать. Не вижу смысла в ограничении этой возможности.

Добавлено через 8 минут и 22 секунды
И потом: что значит стирается информация о переопределённых членах? Члены просто перестают быть виртуальными?


--------------------
Хочешь получить мудрый совет - читай подписи участников форумов.
Злой доктор Щасзаболит smile
PM   Вверх
PashaPash
Дата 3.11.2008, 13:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1233
Регистрация: 3.1.2008

Репутация: 13
Всего: 49



Цитата(Dims @  3.11.2008,  12:28 Найти цитируемый пост)
А что значит "известен" внешний интерфейс? Ведь это же не означает просто, что известны имена методов и типы их параметров. Это означает, что известно, и что эти методы ДЕЛАЮТ. Например, метод "длина" класса "вектор" вычисляет длину вектора. 

ЧТО делает не означает КАК делает. Если метод длина использует внутри метод "нарисовать" и "подсчитать клетки в нарисованном векторе" (для примера), то эти методы не должны быть видны извне. Подход "явно указать что видно извне" просто безопаснее с точки зрения архитектуры чем, "все сделать видимым извне, а потом закрывать доступ". Потому что урезать интерфейс после публикации довольно сложно - всегда есть шанс что на него кто-то уже привязался.
Скажем так - в java не было выбора virtual/not virtual. В C# есть выбор, и по умолчанию он сделан в сторону решения, несущего меньше потенциальных последствий. Никто тебя ни к чему не заставляет и не принуждает smile

Цитата(Dims @  3.11.2008,  12:28 Найти цитируемый пост)
То есть, Вы утверждаете, что разработчики C# не продумывали свойства языка, а просто сделали не так как в Java?

Не так - не всмысле "специально сделали через ж, чтобы от java отличаться". Не так - значит продумали, рассмотрели решения в 3-4х OO-языках и выбрали лучшее. Поэтому не стоит удивляться что что-то "не так".
Цитата(Dims @  3.11.2008,  12:28 Найти цитируемый пост)

Однако, эти вещи были специально созданы разработчиками, имея в виду какие-то мысли. Может быть, мысли и ошибочные, но они были. А в Вашем описании C# это вещь в себе, которая не произошла ни от кого и функции которой просто есть, нипочему.

Я совершенно с этим не согласен. Я думаю, что и тут были какие-то мысли, просто мы их не знаем. Почему просто в этом не признаться?

Просто C#/.NET вышел позже чем Java, и его создатели попытались решить некоторые проблемы OOP, о которых до появления Java никто не задумывался. Но это не значит что C# - это Java от MS. C# намного ближе к C++.

Цитата(Dims @  3.11.2008,  12:28 Найти цитируемый пост)
На самом деле, я понял, что такое затенение функций -- это отколовшаяся часть системы преобразования типов.

Проблема в том, что ты все еще считаешь что все функции должны быть виртуальными. Подходи с классической позиции с учетом минимализма интерфейса. Полиморфизм позднего связывания - только один из 2-х видов полиморфизма в OOP, но почем-то единственный в Java. Но на java свет клином не сошелся. smile


--------------------
PM MAIL WWW   Вверх
Dims
Дата 3.11.2008, 14:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1016
Регистрация: 21.11.2006

Репутация: 0
Всего: 11



Цитата(PashaPash @  3.11.2008,  13:45 Найти цитируемый пост)
Если метод длина использует внутри метод "нарисовать" и "подсчитать клетки в нарисованном векторе" (для примера), то эти методы не должны быть видны извне.

Если они не видны извне, то их и нельзя переопределить. Мы же рассматриваем случай, когда метод А виден извне, используется одним из других методов Б и был переопределён в наследнике.

Утверждается, что это плохая ситуация, так как программист наследника не должен знать, что метод Б использует А. 

Я с этим не согласен. Если разработчик предка использовал метод А в методе Б и оставил метод А открытым, то он должен был написать в инструкции, что роль метода А сводится не только к тому, что он делает нечто, но она состоит ещё и в том, что он используется методом Б. Тогда программист наследника, прочтя инструкцию, узнает об этом и будет переопределять А с умом.

Если же это нежелательно, то метод А можно сделать оконечным и тогда никто его не сможет переопределить.

Цитата(PashaPash @  3.11.2008,  13:45 Найти цитируемый пост)
Скажем так - в java не было выбора virtual/not virtual

Зато он был в Си++, опыт которого использовали при создании Джава. То есть, в Джаве специально убрали этот выбор. Намеренно. 

Цитата(PashaPash @  3.11.2008,  13:45 Найти цитируемый пост)
Не так - значит продумали, рассмотрели решения в 3-4х OO-языках и выбрали лучшее.

Ну так это я и имел в виду, под "убрали" или "добавили". Учёт опыта. 

Цитата(PashaPash @  3.11.2008,  13:45 Найти цитируемый пост)
Но это не значит что C# - это Java от MS.

Не переводите вопрос в плоскость религиозных войн. Вы с одной стороны признаёте, что при создании Си-диез учитывался опыт Джавы, а с другой стороны пытаетесь принизить роль этого факта, говоря, что Си-диез это не Джава от МС.

Главные фишки Джавы -- это виртуальная машина, ссылочные типы и сборщик мусора. Всё это есть и в .НЕТ. Причём исторически тоже, сперва Микрософт лицензировало Джаву, сделала свой JIT, затем отказалась от неё, сделала J++ и потом придумало свою платформу NET и C#. Влияние, на мой взгляд, самое, что ни на есть прямое. Ну примерно как в СССР при создании ЕС использовали IBM 360. Учитывая производственные мощности Микрософта и их наработки, просто неизбежно должно было произойти какое-то столкновение видений и была должна получиться своя масштабная и полноценная платформа.

Цитата(PashaPash @  3.11.2008,  13:45 Найти цитируемый пост)
Проблема в том, что ты все еще считаешь что все функции должны быть виртуальными.

Это не проблема, а моё мнение. ;)

Цитата(PashaPash @  3.11.2008,  13:45 Найти цитируемый пост)
Полиморфизм позднего связывания - только один из 2-х видов полиморфизма в OOP, но почем-то единственный в Java.

На мой взгляд, связывание имеет отношение не к ООП, а к реализации. В моём гипотетическом языке компиллятор осуществлял бы раннее связываение при одном преобразовании типов и позднее -- при другом.
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.1183 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.