![]() |
Модераторы: Partizan, gambit |
![]() ![]() ![]() |
|
Dims |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
В Си++ было так, что если в подклассе определяешь функцию с такой же сигнатурой, что и в надклассе, то ничего не происходило, функция просто перекрывала надфункцию для кода внутри подкласса.
Чтобы функция подменялась, её нужно было определять, как виртуальную. В Джаве все функции виртуальные и ничего писать для этого не надо. Каковы функции в С#? |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Если нужно, чтобы функция была виртуальной надо указать virtual, а если она абстрактная - указываем abstract, а в производном классе переопределяемую функцию надо пометить как override? для затенения используется new
-------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Dims |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
А зачем может быть нужно затенение?
|
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Перопределить можно только абстрактные и виртуальные члены класса. Если по какой-либо причине в производном классе нужен например метод, имеющий определённую сигнатуру, а в базовом классе есть такой метод, но он не нужен и не является ни абстрактным, ни виртуальным, то используется затенение. Это даёт возможность избежать конфликтов имён.
-------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Partizan |
|
|||
![]() Let's do some .NET ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2828 Регистрация: 19.12.2005 Где: Санкт-Петербург Репутация: 18 Всего: 67 |
Использование ключевого слова new по сути вас просто избавит от надоедливого warning-a, выдаваемого студией
![]() -------------------- СУВ, Partizan. |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Ну тут есть и практический аспект. Допустим надо создать класс, наследующий какой-то другой класс, в котором определено много разных членов. Естественно помнить их все наперечёт трудно, да и ни к чему.
Далее разработчик включает в класс свой метод, в то время как такой же метод есть в базовом классе. Допустим студия молчит, метод затеняется без предупреждений, а после этого класс используется другими разработчиками, которые смотрят, от чего унаследован класс и естественно используют члены , унаследованные от базового класса. Вызывают затенённый метод и эффект от него оказывается неожиданным. А на этом методе в программе может быть много чего завязанно. Поэтому указание, что метод затенён - скорее сообщение компилятору, что разработчик выбрал имя не по ошибке, а напротив знает, что делает, и делает это намеренно. Я бы так сформулировал. -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
VK_Techno |
|
|||
Новичок Профиль Группа: Участник Сообщений: 10 Регистрация: 29.9.2007 Репутация: нет Всего: нет |
и покажет, что в производном классе намеренно скрыт метод / поле / свойство / etc. из класса-предка. |
|||
|
||||
Partizan |
|
|||
![]() Let's do some .NET ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2828 Регистрация: 19.12.2005 Где: Санкт-Петербург Репутация: 18 Всего: 67 |
VK_Techno, это да...но я имею виду, что всё будет нормально работать и без использования new...
-------------------- СУВ, Partizan. |
|||
|
||||
QryStaL |
|
|||
![]() Intellectual feast ![]() ![]() Профиль Группа: Участник Сообщений: 914 Регистрация: 30.11.2005 Репутация: 14 Всего: 32 |
Кроме этого, new используется для "прерывания" цепочки наследования и начала ее заново - в таком случае пишется new virtual. Еще бывают извраты типа new abstract.
![]() -------------------- I don't need a reason being who I am... |
|||
|
||||
diadiavova |
|
||||||||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Можно, конечно, и для "прерывания", только на самом деле цепочка не прерывется. Члены продолжают наследоваться, только к ним нет прямого досткпа. В качестве илюстрации приведу пример. Создаём 3 класса a, b и с. b наследуется от a, c - от b. В классе a определяем метод GetClassName, который будет возвращать строку "Класс а", в классе b затеняем этот метод, теперь он возвращает строку "Класс b". Один нюанс в классе а метод помечаем как public, а в классе b как private. И во всех трёх классах определяем свойство ClassName которое будет вызывать функцию и возвращать её значение.
далее создаём экземпляры классов и смотрим, что возвратит свойство у каждого из них (особенно интересен класс с)
дальше значение переменной s выводим для просмотра
Таким образом не смотря на то, что в классе b мы затенили метод GetClassName private - методом с той же сигнатурой, в производном классе с тем не менее спокойно вызывается метод который ранее был затенён. Просто теперь, когда затеняющий метод не виден, мы снова получили доступ к затенённому методу. -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
||||||||
|
|||||||||
QryStaL |
|
|||
![]() Intellectual feast ![]() ![]() Профиль Группа: Участник Сообщений: 914 Регистрация: 30.11.2005 Репутация: 14 Всего: 32 |
Про наследование спору нет. Имелся в виду вызов соответствующего метода при приведении типов и полиморфном вызове. -------------------- I don't need a reason being who I am... |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Я и не пытался спорить, просто определение звучит несколько двусмысленно, поэтому я просто пояснил. -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
QryStaL |
|
|||
![]() Intellectual feast ![]() ![]() Профиль Группа: Участник Сообщений: 914 Регистрация: 30.11.2005 Репутация: 14 Всего: 32 |
Ок. =) Вроде выяснили, теперь слово за автором темы... -------------------- I don't need a reason being who I am... |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Да я чойта подзреваю, что вопросы ещё будут. Тема мутная.
![]() -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Dims |
|
||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
Ну это получается какое-то шаманское объяснение. Причины и следствия какие-то отвлечённые от жизни. Вот я уже давным давно программирую на Джаве и ни разу не пожалел, что там все функции виртуальные. Наоборот, это позволяет избежать потенциальных конфликтов, поскольку к объекту данного класса всегда будет вызывать его метод, написанный именно для него, независимо от того, к какому типу приведён объект. Добавлено через 5 минут и 34 секунды
Ну тут не вопрос, они, конечно, молодцы, что сделали ключевое слово override. Вопрос в том, зачем может понадобиться затенение? Чего оно такого может, чего не может обычное введение новой функции? Добавлено через 11 минут и 34 секунды
А зачем? Допустим, у нас все функции виртуальные. Никакой цепочки же нет. В каждом классе есть своя функция, либо он использует функцию базового класса. Цепочка возникает тогда, когда в методе наследника вызывается перекрытый метод предка. Ну тут уж программист явно написал, значит, хотел. Я прекрасно помню, зачем это нужно было в Си++ -- чтобы экономить память. Для хранения виртуальной функции нужен, как вариант, указатель на неё. Это добавляет байты в структуру описания класса, так как каждый класс должен помнить свою версию функции. А невиртуальная функция определяется типом объекта, к которому она применяется. Так что её помнить не надо, она вставляется на этапе компилляции. |
||||
|
|||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Дело в том, что переопределённая виртуальная функция - это та же самая функция, для которой было изменено поведение. Не знаю как всё устроено в жабе(знаком обзорно), но в дотнете это может привести к неприятностям. Если функция помещена в класс просто для того, чтобы её могли использовать будущие поколения - то не страшно. Но если эта функция используется самим базовым классом, и влияет на его поведение, то её переопределение может привести к непредсказуемым последствиям. Поскольку программист не всегда знает детали реализации базового класса, то учесть все последствия переопрделния он не может. И понять источник проблем тоже. Когда метод затеняется он продолжает работать в классе и передаётся потомкам, просто к нему нет прямого доступа, но если он используется в базовом классе - он не будет лежать мёртвым грузом, а будет работать. В то же время метод с такой же сигнатурой может быть предоставлен для использования. Затенённый и затеняющий методы - два разных метода, имеющих одинаковую сигнатуру и находящихся в одной области видимости(в следствии чего один из них не виден). Переопределённый метод - это тот же самый метод, для которого в производном классе определен другой тип поведения.
-------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Dims |
|
||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
В Джаве функции переопределяются не для будущих поколений, а для полиморфизма, то есть, чтобы можно было работать с объектом не зная точно его типа. Для любого объекта, независимо от того, что нам в данный момент известно о его типе будет вызываться именно его метод. Это же логично.
Для этого есть слово final, которое запрещает переопределение функции. Если у нас такая функция, которая используется самим классом и вредно, чтобы она "знала правду" о классе, тогда мы делаем её final. Всё, теперь такого не случится. А в обратном случае это может даже помочь. Мы можем нарочно определить функцию, которая используется в базовом классе но в расчёте на возможное переопределение в наследниках. Тогда наследник сможет влиять на поведение вызывающей функцией базового класса. А к каким последствиям, по-Вашему, может привести первый сценарий? Можете придумать пример?
Мне кажется, это нелогично. Если человек не знает свойств базового класса, то зачем он взялся его переопределять? Пусть тогда напишет обёртку, а не наследника. Кроме того, если наследование чревато, то, значит, разработчик базового класса не позаботился о том, чтобы его класс можно было легко расширять.
Я это понимаю, всё-таки с Си++ знаком. Вопрос в том, нафига это нужно. Зачем нужен такой же метод, но делающий совершенно другое? По логике, метод должен быть спроектирован и назван так, чтобы было понятно его предназначение. Если у метода другое предназначение, то нужно его назвать по-другому. По Си++, повторяю, мне кажется, что причина была в экономии памяти. Всё-таки Си -- это макроассемблер, а Си++ это Си с классами. То есть, Си++ это ассемблер с классами. При программировании на Си++ можно (и желательно) представлять, что происходит с байтами, сколько занимает класс, как он расположен в памяти и так далее. А виртуальные функции вносят сумятицу в "ассемблерность". Поэтому для Си++ они лишь опция. А почему они лишь опция для C#? |
||||||||
|
|||||||||
diadiavova |
|
||||||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
В дотнете это всё тоже есть и такой подход даже является главенствующим, однако дополнительные возможности , насколько я понимаю "жрать не просят". Когда я писал обудущих поколениях я имел в виду функции, которые не вызываются базовым классом, а предоставлены для использования производными. Относительно final, в до-диезе есть слово sealed которое(как я понимаю) деделает то же самое. Но если мне надо создать метод, переопределение которого будет иметь неблагоприяятные последствия из-за того, что в базовом классе этот метод вызывается в расчёте на определённое поведение и вдруг в производном классе это поведение изменяется. Чтобы этого избежать я просто не даю такой возможности и не делаю метод виртуальным. Что в этом плохого? Если в жабе тоже есть такая возможность, то это говорит только о том, что различия здесь в том, какими функции считаются по умолчанию: в жабе - виртуальными, в дотнете - нет. И там и тут это можно изменить. Только в дотнете ещё можно и создать такую же функцию. Насчёт упаковывания класса - хорошая задумка, особенно если в нём пара сотен членов и все надо упаковать, а в дотнете вместо этого надо упаковать всего-лишь один метод, к тому же затенённый метод можно вызвать из затеняющего(это не проблема). Ну для этого и есть виртуальные методы, в дотнете они тоже так работают(учитывая происхождение дотнета вряд ли стоит этому удивляться).
Ну например такая ситуация: Внутренний метод, вызывающий переопределённую функцию расчитывает на то, что значение ею возвращённое будет лежать в пределах определённого диапазона значений. Другое не предусмотренно из соображений экономии ресурсов. Переопределённый вариант функции(в отличии от первоначального) может возвращать значение, к которому вызывающий метод просто не готов. Естественно это вызовет сбой. Конечно пример не очень показательный, но по крайней мере ясно, что я имею в виду.
А от куда он может знать свойства? Если функция помечена как виртуальная - он знает, что её можно переопределить. Если нет - знает, что нельзя. Тут по-моему как раз всё просто.
Да нет. Как раз таки он позаботился, определив какие члены класса можно переопределять, а какие нет. Я не сказал, что он будет делать совершенно другое. Чуть-чуть другое, или просто по-другому, или например делая тоже самое(скажем посредством вызова затеняемого метода), при этом ещё инициировать какое-нибудь событие, да и вообще мало ли что ещё может понадобиться. Иногда бывает надо закрыть метод просто из-за того, что его вызов может не вписаться в логику класса и просто надо его перекрыть, например методом с пустой реализацией. И потом, в таком случае, почему не вызывает вопросов возможность перегрузки методов? Зачем нужно два метода с одинаковыми именами? Вариантов может быть много, хотя затенением я не пользуюсь, возможно именно по этому не могу привести какой-то яркий пример, но если так рассуждать "зачем нужно то, да зачем нужно это", то так можно очень далеко зайти. К примеру: зачем нужны модификаторы области видимости, когда можно просто не использовать те которые трогат нельзя, а зачем их прятать? Вопрос звучит странно, но он из того же набора, если мне не нужно, чтобы метод переопределяли - я не даю такой возможности Что значит "лишь опция"? Почему по-умолчанию они должны быть виртуальными? Потомучто в жабе так? Учитывая тот факт, что дотнет (мягко говоря) взял много из жабы, то наверно там это доставляло какие-то неудобства, раз уж это изменено. -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
||||||
|
|||||||
Dims |
|
||||||||||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
Я не знаю. Просто мне пока непонятно, зачем это может быть нужно и оно кажется нелогичным. Если брать двоих: потомка и предка, то, по логике, потомок всегда знает больше предка. Поэтому, бояться, что знающий больше что-то напортачит, нелогично. Кроме того, затенение само по себе чревато ошибками: если мы приведём наследника к типу предка, что совершенно допустимо и не должно приводить ни к каким плохим последствиям, и вызовем метод, то вызовется затенённый метод. То есть, метод предка отработает на материале наследника, что чревато гораздо более серьёзными глюками, так как предок в принципе не может ничего знать о наследнике. Но даже если возможности просто не нужны, то они "просят жрать" в том смысле, что требуют ресурсов, а взамен ничего не дают. Например, требуют от меня набирать слово "virtual". В том-то и дело, что в Джаве это нельзя изменить. Все функции всегда виртуальные.
Я так понимаю, что современные генераторы делают это автоматически. Мы же говорим о ситуации, когда разработчик не знает поведения базового класса и боится, что переопределение какой-то функции приведёт к нежелательным последствиям. Это значит, скорее всего, что ему и не нужны все 100 членов (раз он неосведомлён о том, что они делают). Всё же это абстрактная ситуация. Где конкретно такое может произойти? Как правило, наследник более специфичен, а это значит, что диапазон возвращаемых значений должен только сужаться. Например, функция "Рост" для "Животного" может возвращать значение от миллиметров до десятков метров. А та же функция для "Человека" примерно от метра до двух. Как может получиться так, что частный случай возвращает больший спектр значений, чем общий? Если это происхожит, то это, наверное, не частный случай. В этом случае функцию просто, наверное, нужно назвать по-другому.
Ну это правильно, но если функция не помечена, как виртуальная, то её можно затенить. И зачем нужна эта возможность -- непонятно. Ну а как же тогда? По логике ООП наследник -- это некто более осведомлённый. Частный случай предка. Его методы -- они либо повторяют методы предка, либо делают что-то более частное, детальное, что на уровне предка сделать было нельзя. Такая эволюция методов логична.
Ну а причём тут затенение? Виртуальная функция точно так же может вызвать перекрытый метод, разве нет? Для этого затенение не нужно.
С одинаковыми именами, но с разными сигнатурами. Как правило, такие методы должны делать одно и тоже с разными исходными данными. А как же? Объявляете все функции виртуальными?
Ну я не знаю, куда можно зайти ![]() Соответственно, когда какие-то вещи, которые были убраны и по которым ты совсем не скучал, возвращаются, неизбежно возникает вопрос, нафига. Это чё такое? public/private?
Минуточку, но это ведь как раз Вы говорите, что что плохого в затенении, если его можно просто не использовать. Повторюсь, что слово override мне нравится. Оно добавляет проверку (кстати, если они любители проверок, то нафига убрали throws? в джаве есть два типа Exception, одни из них обязательно описывать в сигнатуре метода при помощи слова throws; то есть, ты смотришь на метод и видишь, чего он выбрасывает)
Как Вы можете не дать затенять? Ну если это единственная полезная их форма, то разве это не основание?
Ну так давайте выясним, какие. Разве это не интересно? |
||||||||||||||||
|
|||||||||||||||||
diadiavova |
|
||||||||||||||||||||||||||||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Потомок может и знает, только код этого потомка пишет программист, который знает не всё. Наследник должен создаваться с учётом поведения предка. Предок же не может заранее знать, что прийдёт в голову программисту который будет реализовывать наследование, поэтому логично некоторые действия просто запретить. Но запрещать создавать методы с определённой сигнатурой не стали, дабы расширить возможности. Ну к затеняющему методу можно относиться как к перегруженному. Перегруженные методы - это тоже разные методы, а одно имя им даётся намеренно, именно потому, что они делают одно дело но по-разному. Ну если не набирать это слово, тогда компилятору будет не понятно почему программист создал метод с существующим именем: по-ошибке или намеренно. Полиморфизм - это хорошо, а если я просто создаю метод для поддержки какой-то функциональности и мне не надо, чтобы его переопределяли. Ядолжен каждый раз об этом уведомлять словом final? По моему гораздо проще реализовать метод без учёта того, что он может быть переопределён. Я например виртуальные методы создаю как раз в тех случаях, когда именно на то и расчитываю, что потом можно будет переопределить их, но там продумывается логика и все возможные нюансы возможной(!) реализации в производном классе. Гораздо проще написать метод под конкретные задачи, да и ресурсов он меньше жрёт, потомучто не проверяет тех возможностей, которых не должно быть в случае, если всё пойдёт как я задумал. В виртуальном методе всё это надо учитывать.
Тогда я не понял, что такое final. Ему не члены нужны а сам класс. Возможно он вообще должен быть определённого типа там где используется. Базовый класс вообще может быть абстрактным, а реализуется только потому, что какой-то метод затребовал в качестве параметра экземпляр класса производного от данного, да вариантов море. Надо мне конрол создать, не знаю всех нюансов поведения, сделаю упаковку , и куда я с ней? В коллекцию Controls её не добавишь, что мне эту упаковку сбоку пристраивать чтоли, а если некоторые методы надо переопределить, как это реализовать с упаковкой? Да и потом мне не ясна такая логика, когда написать virtual трудно, а создавать упаковку, даже если генерить код автоматом - легко.
Если оба класса пишет один человек - такого быть не должно. Но это не всегда так. Насчёт специфичности класса я не согласен. Потомок расширяет базовый класс(кстати в jscript.net для указания базового класса используется слово exteds). Если считать, что производный класс сужает возможности(как в примере с ростом) тогда самым богатым классом должен быть Object, а все остальные более специфичными, ну это же не так.
Это точно не частный случай. А функцию можно назвать и по-другому, но можно и так же(если надо).
Возможность эта нужна за тем же зачем и переопределить. Если нужно, чтобы в производном классе была такая функция, но выполняла другие действия, то эту функцию создают. Если функция виртуальная, то эту новую функцию можно оформить как переопределяющую(не обязательно виртуальные функции тоже можно затенять), а в остальных случаях она будет затенять соответствующую функцию базового класса. Я подчёркиваю: в обоих случаях делается одно и то же. Разница состоит в том, что при переопределении все вызовы, определённые в базовом классе, будут обращаться к новой версии функции, а при затенении - к старой. Но новая реализация функции имеет место в обоих случаях. То есть: возможность затенения нужна для того, чтобы при создании такого же метода в производном классе, поведение базового, завязанное на ней не менялось. Я бы сказал не что-то более частное, а скорее, что-то сходное по логике, но иногда совсем другое. Что-то, что может быть тем же, что и в базовом классе, только применительно к другому контексту.
Может, только как я уже сказал, базовый класс тоже будет её вызывать. А пример я привёл для того, чтобы показать, что метод не только не делает что-то другое, аможет вести себя так же как виртуальный, даже вызывать затеняемый метод, другой вопрос, что его не будет вызывать базовый класс.
Как правило - это тоже ни кчему не обязывает, а потом я не говорил, что затеняющий метод должен делать что-то другое, по-другому - да. Нет, только те, которые собираюсь переопределять. Вся фишка в том, что как правило в затенении нет необходимости, но если она возникает, то у меня есть возможность создать в производном классе функцию с нужной сигнатурой, не затрагивая болевых точек базового класса. И хорошо, что она есть. Я понимаю, что без этого, наверно можно обойтись, но это удобно. Если переопределение функции опасно - я лишён такой возможности. Разве это плохо? Сколько косяков можно напороть просто из-за незнания всех возможных опасностей. В современных языках в основном приходится работать с огромным количеством библиотечных классов, знать все нюансы поведения которых, просто невозможно. И если там есть ограничения, то это приводит просто к тому, что я не могу сделать некоторых вредных штук. Взять например зоопарк. Звери сидят в клетках, чтоб никого не растерзали, но на расстоянии от клетки стоит ограда для людей, чтобы они не подходили близко. Ограничение свободы? Да. Хорошо это или плохо в данном случае? Ну может от этого она не очищена, просто там до этогоне додумались? ![]() А если учесть, что у дотнета ноги из жабы растут... Угу =========== Насчёт trows я не понял, но в дотнетовских языках это тоже есть, не знаю, может в жабе есть варианты... А зачем? Не давать переопределять нужно для того, чтобы вызовы базового класса не получали подмену, а зачем не давать затенять? Затенение - другой метод. Пусть создают сколько влезет методов(или других членов) с такими же сигнатурами, на поведение, определённое в базовом классе это не повлияет. Запрещать затенение - это всё равно, что запрещать создавать члены с определёнными именами. Это ничего не даст. А вот запрет на изменение логики на какю-то неожиданную, может оказаться полезным. Эта форма не единственная полезная, и кроме того - потенциально опасная. Да в общем-то этим и занимаемся уже несколько дней. ![]() Добавлено через 10 минут и 18 секунд
Потомок может и знает, только код этого потомка пишет программист, который знает не всё. Наследник должен создаваться с учётом поведения предка. Предок же не может заранее знать, что прийдёт в голову программисту который будет реализовывать наследование, поэтому логично некоторые действия просто запретить. Но запрещать создавать методы с определённой сигнатурой не стали, дабы расширить возможности. Ну к затеняющему методу можно относиться как к перегруженному. Перегруженные методы - это тоже разные методы, а одно имя им даётся намеренно, именно потому, что они делают одно дело но по-разному. Ну если не набирать это слово, тогда компилятору будет не понятно почему программист создал метод с существующим именем: по-ошибке или намеренно. Полиморфизм - это хорошо, а если я просто создаю метод для поддержки какой-то функциональности и мне не надо, чтобы его переопределяли. Ядолжен каждый раз об этом уведомлять словом final? По моему гораздо проще реализовать метод без учёта того, что он может быть переопределён. Я например виртуальные методы создаю как раз в тех случаях, когда именно на то и расчитываю, что потом можно будет переопределить их, но там продумывается логика и все возможные нюансы возможной(!) реализации в производном классе. Гораздо проще написать метод под конкретные задачи, да и ресурсов он меньше жрёт, потомучто не проверяет тех возможностей, которых не должно быть в случае, если всё пойдёт как я задумал. В виртуальном методе всё это надо учитывать.
Тогда я не понял, что такое final. Ему не члены нужны а сам класс. Возможно он вообще должен быть определённого типа там где используется. Базовый класс вообще может быть абстрактным, а реализуется только потому, что какой-то метод затребовал в качестве параметра экземпляр класса производного от данного, да вариантов море. Надо мне конрол создать, не знаю всех нюансов поведения, сделаю упаковку , и куда я с ней? В коллекцию Controls её не добавишь, что мне эту упаковку сбоку пристраивать чтоли, а если некоторые методы надо переопределить, как это реализовать с упаковкой? Да и потом мне не ясна такая логика, когда написать virtual трудно, а создавать упаковку, даже если генерить код автоматом - легко.
Если оба класса пишет один человек - такого быть не должно. Но это не всегда так. Насчёт специфичности класса я не согласен. Потомок расширяет базовый класс(кстати в jscript.net для указания базового класса используется слово exteds). Если считать, что производный класс сужает возможности(как в примере с ростом) тогда самым богатым классом должен быть Object, а все остальные более специфичными, ну это же не так.
Это точно не частный случай. А функцию можно назвать и по-другому, но можно и так же(если надо).
Возможность эта нужна за тем же зачем и переопределить. Если нужно, чтобы в производном классе была такая функция, но выполняла другие действия, то эту функцию создают. Если функция виртуальная, то эту новую функцию можно оформить как переопределяющую(не обязательно виртуальные функции тоже можно затенять), а в остальных случаях она будет затенять соответствующую функцию базового класса. Я подчёркиваю: в обоих случаях делается одно и то же. Разница состоит в том, что при переопределении все вызовы, определённые в базовом классе, будут обращаться к новой версии функции, а при затенении - к старой. Но новая реализация функции имеет место в обоих случаях. То есть: возможность затенения нужна для того, чтобы при создании такого же метода в производном классе, поведение базового, завязанное на ней не менялось. Я бы сказал не что-то более частное, а скорее, что-то сходное по логике, но иногда совсем другое. Что-то, что может быть тем же, что и в базовом классе, только применительно к другому контексту.
Может, только как я уже сказал, базовый класс тоже будет её вызывать. А пример я привёл для того, чтобы показать, что метод не только не делает что-то другое, аможет вести себя так же как виртуальный, даже вызывать затеняемый метод, другой вопрос, что его не будет вызывать базовый класс.
Как правило - это тоже ни кчему не обязывает, а потом я не говорил, что затеняющий метод должен делать что-то другое, по-другому - да. Нет, только те, которые собираюсь переопределять. Вся фишка в том, что как правило в затенении нет необходимости, но если она возникает, то у меня есть возможность создать в производном классе функцию с нужной сигнатурой, не затрагивая болевых точек базового класса. И хорошо, что она есть. Я понимаю, что без этого, наверно можно обойтись, но это удобно. Если переопределение функции опасно - я лишён такой возможности. Разве это плохо? Сколько косяков можно напороть просто из-за незнания всех возможных опасностей. В современных языках в основном приходится работать с огромным количеством библиотечных классов, знать все нюансы поведения которых, просто невозможно. И если там есть ограничения, то это приводит просто к тому, что я не могу сделать некоторых вредных штук. Взять например зоопарк. Звери сидят в клетках, чтоб никого не растерзали, но на расстоянии от клетки стоит ограда для людей, чтобы они не подходили близко. Ограничение свободы? Да. Хорошо это или плохо в данном случае? Ну может от этого она не очищена, просто там до этогоне додумались? ![]() А если учесть, что у дотнета ноги из жабы растут... Угу =========== Насчёт trows я не понял, но в дотнетовских языках это тоже есть, не знаю, может в жабе есть варианты... А зачем? Не давать переопределять нужно для того, чтобы вызовы базового класса не получали подмену, а зачем не давать затенять? Затенение - другой метод. Пусть создают сколько влезет методов(или других членов) с такими же сигнатурами, на поведение, определённое в базовом классе это не повлияет. Запрещать затенение - это всё равно, что запрещать создавать члены с определёнными именами. Это ничего не даст. А вот запрет на изменение логики на какю-то неожиданную, может оказаться полезным. Эта форма не единственная полезная, и кроме того - потенциально опасная. Да в общем-то этим и занимаемся уже несколько дней. ![]() -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||
PashaPash |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
Dims,
По логике потомок не знает больше предка, скорее к ним применимо "потомок есть предок". Человек, пишущий класс-предок, знает его public/protected интерфейс и внутреннюю реализацию. Человек, пишущий класс-потомок, знает о предке только public/protected интерфейс и ничего не знает о реализации. И, соответственно, не должен никак на эту реализацию влиять, если это явно не разрешил автор предка. Значения по умолчанию направлены на уменьшение интерфейса класса/сборки - private/internal вместо public, невиртуальные вместо virtual. Вообще, с точки зрения ООД наследование настолько увеличивает связность и тянет за собой столько ошибок, что надо классы по умолчанию sealed объявлять. Вот именно поэтому и выводится warning, и требуется необязательное слово new. Просто надо воспринимать warnings as errors ![]() Набирая слово virtual, ты явно увеличиваешь площадь интерфейса. Во время набора нужно подумать что будет, если потомок реализует этот метод по-своему. Учесть что у автора потомка не будет знаний о внутреннем устройстве твоего класса. Учесть что через год какой-нибудь нуб придет и переопределит этот метод через 4 класса в цепочке наследования, при этом все 4 будут написаны тобой и будут завязаны на внутренее устройство родителя. Возможные проблемы гораздо круче чем проблемы при игнорировании варнинга "нужен new". Поэтому и слово длиннее на 4 буквы, чтобы больше времени было ![]() Затем, что классы-потомки могут бросать исключения, не описанные в синатуре предков. И еще затем, чтобы уменьшить связность и проблемы с версиями. В .net можно подменить, например, сборку с базовым классом даже если сборка потомка явно привязана к ее версии. И в момент выполнения список throws оказался бы совсем не таким, как в момент компиляции. В java фишек с версиями нет, там throws проверяется только в compile time. Это сообщение отредактировал(а) PashaPash - 28.10.2008, 10:46 |
|||
|
||||
Dims |
|
||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
Это было в Си++, потом это убрали в Джаве, а потом обратно вернули в C#. Джава произошла от Си++, а C# от них обоих.
Я не знаю. Я не знаю ни зачем не давать затенять, ни зачем давать. В Си++ я понимаю, зачем сделано затенение, а зачем в C# не понимаю. Добавлено через 8 минут и 30 секунд
Правильно. Но если ему в инструкции сказано, что переопределив такой-то метод он добьётся такого-то результата, то он кое-что знает и о реализации.
Ну давайте тогда уберём спецификацию возвращаемого типа, чтобы потомки могли и возвращать объекты другого типа. Ну ладно, это отклонение. В этой теме давайте разберёмся, зачем нужно затенение. |
||||||||
|
|||||||||
PashaPash |
|
||||||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
Основной принцип ооп - о классе известен только его внешний интерфейс. Если в интрукции сказано что переопределение метода как-то повлияет на результат, то это значит все то же - что метод - часть public интерфейса класса. И никак не значит, что наследник что-то узнает о реализации. Если для наследования нужно нарушить инкапсуляцию, то это какое-то не ооп-ное наследование. На самом деле вопрос примерно на уровне: А почему методы не public по умолчанию? в языке xxx все методы pubic, очень удобно. Ну и что, что программер может не знать зачем они нужны. Никто ж не заставляет его их вызвать, да и автору базового класса легче - не надо писать дурацкие public. Да, в .net/java есть возможность сделать метод public, но зачем нужны private методы, это ж неудобно.
в jave бросаемые исключения - часть интерфейса, т.е. подразумевается что они могут возникать при обычном ходе выполнения программы. В .net исключения - это именно исключительные ситуации, и они не являются частью интерфейса. На самом деле код очень редко может нормально обработать исключение, и принудительное перечисление типов приведет к желанию программеров тупо исключения глушить. И код очень редко знает полный список исключений, которые может бросить вызываемый им кусок. Кроме кода на границе слоев, ес-но
С таким же успехом можно утверждать что C# произошел от Eiffel или от Modula. C#/.NET - не наследник java, это самостоятельная платформа. Ничего в нем не "убирали" и не "добавляли". В нем все так и было с самого начала. И вопросы с позиции "почему тут не так, как в java" имеют общий ответ: потому что это не java, не java от MS, и не наследник Java. И потому что в java тоже есть просчеты с точки зрения дизайна платформы - хотя бы дурацкое выделение элементарных типов, обязательное перечисление исключений, проблемы с версионностью, вирутальные по умолчанию... C# не обязан копировать из java ее проблемы. |
||||||
|
|||||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
А зачем такие сложности, когда можно просто запретить и всё(как в зоопарке) Проблема именно в том, что в этой теме мы смешали в кучу несколько близких тем. Это вносит некоторый сумбур. 1.Почему не все методы виртуальные? Насколько я понял в жабе либо все методы виртуальны, либо класс вообще не наследуется. В дотнете, в противовес этому, механизм наследования можно настроить тонко. То есть при написании класса автор сам определяет что можно переопределить, а что надо оставить без изменений. На мой взгляд - дотнетовский подход более гибкий, чем "всё или ничего". 2. Зачем нужно затенение? В общем то это следует из первого вопроса. Если возникает ситуация, в которой необходима собственная реализация метода, а он не виртуальный, то существует возможность это реализовать не затрагивая функций базового класса, завязанных на реализации данного метода в базовом классе. 3. Почему методы не виртуальны по-умолчанию? Реализация функциональности завязанная на виртуальных методах требует учёта того, что они могут быть переопределены. Реализовать функциональность под конкретные задачи - проще и экономичнее, чем проверять все возможные(и невозможные) последствия переопределения. ЗЫ PashaPash, нам скоро с гастролями можно будет выступать. Как Терренс и Филипп. ![]() -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Dims |
|
||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
А что значит "известен" внешний интерфейс? Ведь это же не означает просто, что известны имена методов и типы их параметров. Это означает, что известно, и что эти методы ДЕЛАЮТ. Например, метод "длина" класса "вектор" вычисляет длину вектора. Нет, вопрос совсем на другом уровне. То есть, Вы утверждаете, что разработчики C# не продумывали свойства языка, а просто сделали не так как в Java?
Однако, эти вещи были специально созданы разработчиками, имея в виду какие-то мысли. Может быть, мысли и ошибочные, но они были. А в Вашем описании C# это вещь в себе, которая не произошла ни от кого и функции которой просто есть, нипочему. Я совершенно с этим не согласен. Я думаю, что и тут были какие-то мысли, просто мы их не знаем. Почему просто в этом не признаться? Добавлено через 51 секунду
Мы разбираем не вопрос как запретить, а вопрос как разрешить. И зачем. Добавлено через 4 минуты и 49 секунд На самом деле, я понял, что такое затенение функций -- это отколовшаяся часть системы преобразования типов. Возможны как минимум два преобразования типов от типа наследника к типу предка. При первом преобразовании отражается ситуация, когда программисту просто неважен конкретный тип наследника. В этом случае он хочет работать с наследником, думая о предке, но при этом чтобы ничего не нарушалось. В этом случае у каждого объекта должна работать своя функция, то есть, все функции должны быть виртуальными. Во втором случае программист может хотеть принудительно превратить наследника в предка, обрубить ему все особенности. В этом случае методы должны браться от предка. |
||||||
|
|||||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Честно говоря: не понимаю, как одно можно рассматривать вне контекста другого. Я говорил всего лишь о том, что ппроще запретить переопределение конкретных членов, чем описывать в документации какие члены переопределять не следует. Конкретный тип не важен тогда, когда в базовом классе либо вообще отсутствуют виртуальные члены, либо те, что есть не переопределены в производном. В этом случае при преобразовании к базовому типу объект ведёт себя так как будто это экземпляр базового типа без каких-либо изменений. Здесь же мы имеем дело с ситуацией, когда переопределёнными могут быть некоторые члены, а остальные - нет. Поведение такого объекта будет отличаться от экземпляров других классов, так же произведённых от данного, в силу того, что в нём таки будут присутствовать виртуальные члены. -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Dims |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
Ну Вы же сами предложили рассмотреть случай -- а вдруг человек переопределит метод и это приведёт к ужасным последствиям. И я полностью с Вами согласен: проще запретить. Это можно сделать и в Джаве при помощи final. А вот когда это не запрещено, как я понимаю, по Вашей теории, и могут быть проблемы. Вопрос: какие? Хочу подчеркнуть, что тут я рассматриваю ситуацию гипотетического языка. Я слышал, что в новом Си++ ввели несколько разновидностей преобразования типов, но ещё не разбирался с ними и не уверен, что это то. Так вот, в этом гипотетическом языке все функции виртуальные, как и в Джаве. А вопрос, какую из них использовать, решается в зависимости от формы преобразования типа. По моим представлениям, после того, как над объектом было проведено "преобразовние к предку первого рода", он не перестал быть потомком. Поэтому, все функции по отношению к нему будут браться от потомка, если они там переопределены. Если к объекту применено преобразование типа "второго рода", то он полностью превращён в предка, а лишняя информация, включая переопределённые функции, стирается. |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Просто тут есть выбор: запрещать всё или только часть. В дотнетовских языках тоже есть возможность запретить дальнейшее наследование класса. Кроме того, здесь есть возможность указать, что в дальнейшем виртуальный член перестаёт быть виртуальным(то есть больше не переопределяется в производных классах). Здесь есть возможность затенения виртуальных членов(выбор между переопределением и затенением). То есть здесь можно всё то же, что и в яве, плюс дополнительные возможности.
Проблемы могут возникнуть именно когда я хочу запретить переопределение пары функций, а мне для этого прийдётся запрещать наследование всего класса. Трудно рассуждать о гипотетическом языке, но в такую модель изначально заложены грабли. Вместо тонкой настройки поведения конкретного класса (в том числе в случае приведения типов), использовать общие правила для всех типов, которые в конкретном случае нельзя изменить... Не думаю, что это наилучшее решение. При желании поведение класса при приведении типов и так можно задать. Не вижу смысла в ограничении этой возможности. Добавлено через 8 минут и 22 секунды И потом: что значит стирается информация о переопределённых членах? Члены просто перестают быть виртуальными? -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
PashaPash |
|
||||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
ЧТО делает не означает КАК делает. Если метод длина использует внутри метод "нарисовать" и "подсчитать клетки в нарисованном векторе" (для примера), то эти методы не должны быть видны извне. Подход "явно указать что видно извне" просто безопаснее с точки зрения архитектуры чем, "все сделать видимым извне, а потом закрывать доступ". Потому что урезать интерфейс после публикации довольно сложно - всегда есть шанс что на него кто-то уже привязался. Скажем так - в java не было выбора virtual/not virtual. В C# есть выбор, и по умолчанию он сделан в сторону решения, несущего меньше потенциальных последствий. Никто тебя ни к чему не заставляет и не принуждает ![]()
Не так - не всмысле "специально сделали через ж, чтобы от java отличаться". Не так - значит продумали, рассмотрели решения в 3-4х OO-языках и выбрали лучшее. Поэтому не стоит удивляться что что-то "не так". Просто C#/.NET вышел позже чем Java, и его создатели попытались решить некоторые проблемы OOP, о которых до появления Java никто не задумывался. Но это не значит что C# - это Java от MS. C# намного ближе к C++.
Проблема в том, что ты все еще считаешь что все функции должны быть виртуальными. Подходи с классической позиции с учетом минимализма интерфейса. Полиморфизм позднего связывания - только один из 2-х видов полиморфизма в OOP, но почем-то единственный в Java. Но на java свет клином не сошелся. ![]() |
||||
|
|||||
Dims |
|
||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
Если они не видны извне, то их и нельзя переопределить. Мы же рассматриваем случай, когда метод А виден извне, используется одним из других методов Б и был переопределён в наследнике. Утверждается, что это плохая ситуация, так как программист наследника не должен знать, что метод Б использует А. Я с этим не согласен. Если разработчик предка использовал метод А в методе Б и оставил метод А открытым, то он должен был написать в инструкции, что роль метода А сводится не только к тому, что он делает нечто, но она состоит ещё и в том, что он используется методом Б. Тогда программист наследника, прочтя инструкцию, узнает об этом и будет переопределять А с умом. Если же это нежелательно, то метод А можно сделать оконечным и тогда никто его не сможет переопределить. Зато он был в Си++, опыт которого использовали при создании Джава. То есть, в Джаве специально убрали этот выбор. Намеренно.
Ну так это я и имел в виду, под "убрали" или "добавили". Учёт опыта. Не переводите вопрос в плоскость религиозных войн. Вы с одной стороны признаёте, что при создании Си-диез учитывался опыт Джавы, а с другой стороны пытаетесь принизить роль этого факта, говоря, что Си-диез это не Джава от МС. Главные фишки Джавы -- это виртуальная машина, ссылочные типы и сборщик мусора. Всё это есть и в .НЕТ. Причём исторически тоже, сперва Микрософт лицензировало Джаву, сделала свой JIT, затем отказалась от неё, сделала J++ и потом придумало свою платформу NET и C#. Влияние, на мой взгляд, самое, что ни на есть прямое. Ну примерно как в СССР при создании ЕС использовали IBM 360. Учитывая производственные мощности Микрософта и их наработки, просто неизбежно должно было произойти какое-то столкновение видений и была должна получиться своя масштабная и полноценная платформа.
Это не проблема, а моё мнение. ;)
На мой взгляд, связывание имеет отношение не к ООП, а к реализации. В моём гипотетическом языке компиллятор осуществлял бы раннее связываение при одном преобразовании типов и позднее -- при другом. |
||||||||
|
|||||||||
PashaPash |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
Проблема такого подхода - слишком много "может" на необходимых для успеха необходимых действиях. Это все на самом деле "может подумать о последствиях переопределения в наследнике, может написать документацию, может упомянуть в ней использование, может быть прочитает инструкцию, может быть будет думать при переопределении". Т.е. для нормального результата нужно много активных действий со стороны 2-х людей. В случае с невиртуальными по умолчанию "может" превращается в "должен". Должет обявить хотя бы protected, должен сделать виртуальной, должен прочитать warning при переопределении, должен написать new. Второй подход IMHO, безопаснее. Скажем, на обсуждаемый вопрос - особенности реализации наследования - больше влияния оказал C++ и COM, чем Java. А в реально существующем C# есть раннее связывание для невиртуальных методов, и позднее - для невиртуальных. И вроде никто (почти) не жалуется. |
|||
|
||||
Dims |
|
||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
От того, что человек напишет слово virtual, он не станет должен написать инструкцию. Он всё равно может проигнорировать эту обязанность. C# требует, чтобы человек явно РАЗРЕШИЛ переопределять функции. А Джава требует, чтобы человек явно ЗАПРЕТИЛ переопределять функции, если это опасно. В обоих случаях человек может наплевать на написание инструкции, которая в обоих случаях необходима. Только при условии, что мы предполагаем, что сплошь и рядом встречаются случаи, когда а) в предке используется метод б) он переопределяется в наследнике в) это нежелательно Я считаю, что это маловероятно. По крайней мере, ситуацию, при которой это так, ещё никто не придумал. Зато гораздо более вероятна ситуация, когда функцию потребуется переопределить, но это будет запрещено, так как программист базового класса забыл написать virtual. Это защитило его от менее вероятной опасности, но так же и не дало возможность получить более вероятную выгоду. Фактически, вот я пишу класс. Если я не объявил класс как sealed, значит, я предполагаю, что от класса будут производить наследников. И если при этом я не подписал все функции как virtual, то я исключил возможность нормального наследования от своего класса. Иными словами, по умолчанию (то есть, без слов sealed и virtual) C# склоняет к созданию классов, непригодных к нормальному (с моей точки зрения) полиморфному наследованию. Отсюда следует, что разработчики C# считают, что наиболее частой является ситуация неполиморфного наследования, то есть, когда функции "затеняются". Отсюда и вопрос: когда это может пригодиться? То есть, когда может пригодиться именно затенение, а не переопределение. Ответа на этот вопрос до сих пор нами не найдено.
Здесь явная опечатка. Когда что? Ну, люди терпят даже такие хаотические языки, как PHP и Perl ![]() |
||||
|
|||||
PashaPash |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
позднее - для виртуальных ес-но. Если ты не можешь увидеть такой ситуации, то значит ты пишешь код по принципу - "одна операция - один метод класса, который не вызывает остальные". Обычная ситуация. Есть метод А, он меняет внутренее состояние вызовом Б. Если методы виртуальные - значит ты готов поставить свою зарплату что кто-то другой всегда сможет корректно переопределить метод А и метод Б. Фактически, это значит что C# склоняет разработчиков ПОДУМАТЬ, перед тем как сделать метод частью public interface. Точно так же, как модификатор доступа private по умолчанию. Т.е. перед тем как позволить кому-то переопределить часть функционала, разработчик обязан обдумать последствия. Подумать что переопределяющий не будет иметь о внутреннем строении твоего класса вообще никакой информации. Ты не видишь негативных последствий - значит код за тобой никогда не дописывали нубы. Я пытался объяснить, что минимизация интерфейса по умолчанию - есть хорошо. Просто рассматривай виртуальные функции с той же стороны, что и как public. Если ты разрешил вызвать функцию - то кто-то ее вызовет. Если ты разрешил ее переопределить - то кто-то ее переопределит, причем совершенно не так, как ты этого ожидал. Ты сейчас отстаиваешь точку зрения которая полностью аналогична "а давайте сделаем public методы по умолчанию". Просто до этого писал на языке, где по умолчанию publiс, и теперь private с твоей точки зрения - ненормальная вещь. Просто пойми, что protected virtual это более широкий досуп к классу, чем public. А "неполиморфным наследованием" - возможностью затенения. Оно используется в исключительных случаях (читай - никогда). Некоторые сидят на JavaScript, с только public методами. И потом им private делает невозможной нормальную (с их точки зрения) работу с объектами ![]() |
|||
|
||||
Dims |
|
||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
Если ты можешь, то опиши её пжлст прямо здесь.
К чему этот пафос? Ещё раз. Подумать -- это всегда полезно. А мы говорим о синтаксических умолчаниях. Как правило, синтаксические умолчания нужны для того, чтобы не указывать чего-то и в результате получить наиболее популярный результат. Если я умалчиваю sealed и умалчиваю virtual -- что я получаю? Класс, в котором при наследоваии методы можно только затенять. То есть, это наиболее распространённая ситуация с точки зрения разработчиков. Ну так опиши же, наконец, для чего она может быть нужна? Повторяю, это должна быть не какая-то ОДНА ИЗ ситуаций, а САМАЯ распространённая, так как она получается в результате умолчания. Вовсе не так же. private по умолчанию, потому что большую часть времени программист проводит в написании внутренней кухни класса. Поэтому private по умолчанию. Это разумно. А зачем по умолчанию non-virtual? Кому нужны кучи классов, в которых нельзя переопределять методы? В таком случае виртуальные функции надо вообще запретить. Ведь так получается по твоей логике. Я, конечно, не отрицаю, что в каких-то случаях злонамеренное или дурное переопределение функций может привести к нарушению работы. Но КАК ПРАВИЛО это не так. И ты это косвенно подтверждаешь тем, что не можешь привести примера, в котором переопределение виртуальной функции вредно.
Это тебе только так кажется.
Ну вот я мог бы объяснить таким людям, зачем нужен private, потому что у меня есть практика их использования. А ты можешь ли объяснить мне, зачем нужно virtual/nonvirtual? |
||||||
|
|||||||
PashaPash |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
Это не пафос, это суровая правда :( Нет, ты получаешь класс в котором методы нельзя подменять без использования затенения. Это не значит что можно затенять методы без очень-очень веской причины. Пролистай стандартные классы .NET - в них очень неплохо продуман интерфейс и при этом - полно невиртуальных функций. Скажем, тот же BackgroundWorker - у него из виртуальных - только вызывающие события. Сравни его со своим воркером из соседнего топика. И сразу вылезет вот такой баг: У тебя в мелком классе всего пару виртуальных функций и уже есть родитель предьявляет требования к особенностям реализации наследника. Вот это - увеличение связности - и есть проблема виртуальных функций и наследования вообще. Наследование - не единственный способ построения дизайна, и даже не самый лучший с точки зрения этого самого дизайна. А виртуальные функции - не единственный способ организации полиморфизма. Не запретить, а сделать невиртуальными по умолчанию. А пример - да вот, прямо в твоем коде ![]() EnsureDataBound/EnsureChildControls который нужно вызывать из наследников, но ни в коем случае нельзя разрешить переопределить. Вообще, открой msdn, любой класс .net. Любая невиртуальная функция - пример. Если над ней подумать - то будут веские причины для ее невиртуальности. Кухня класса - это не только private методы. Это еще и детали реализации для public/protected. Вопрос точно такой же - уменьшение связности и увеличение инкапсуляции. Для этих двух вещей и private и non-virtual - одно и то же. Ок, давай, попробуй объяснить мне, зачем нужен private. Делаем все public. Мои аргументы: Если что - всегда можно прочитать про конкретный метод в документации. Я писал на JavaScript, там все public, все счастливы. Пришел в вашу Java, тут все private по умолчанию. Приведи мне пример, когда public вреден. Что у вас вообще за OOP такое, если нельзя подменить любой кусок имплементации? Какое-то ненастоящее. И на все аргументы - типа инкапсуляция, кухня класса, связность, минимизация интерфейса, скрытие деталей реализации - я буду отвечать "а вот в JavaScript все public, и ничего, очень удобно, и инкапсуляция не нарушаешься. Если что - всегда можно в документации написать.". |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Так разговор об умолчаниях что ли? Я то думал, что вопрос в том, зачем делать метод невиртуальным. А оказывается это вообще не вызывает вопросов, вопрос в том, почему они не виртуальны по-умолчанию.
А так ли это важно вообще? На мой взгляд это разумно, просто потому, что методы могут быть такой же внутренней кухней как private-члены(независимо от видимости), только их ещё можно предоставить в к использованию вне кухни, не мешая работе кухни. Вот и всё. Разработчики явы учли опыт, имевшийся в С++, а разработчики дотнета учли и опыт явы тоже. Результат мы видим. ЗЫ И в javascript есть private члены. -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Да, и ещё.
Я тут в связи с тем, что говорим на эту тему долго, заинтересовался одним вопросом. Попробовал я поискать хоть какую-то возможность вызвать из производного класса, в котором переопределён метод, первоначальную версию этого метода. Прибегал к разным ухищрениям, но такого способа я не нашёл. Не думаю, что это хорошо во всех случаях. -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Dims |
|
||||||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
Так зачем же подменять методы с использованием затенения? Где же тут баг?
Класс всегда предъявляет требования к тем, кто им пользуется, в частности -- к наследникам.
Ну наконец-то ты признался: в Си-диезе намеренно ограничено наследование, так как у наследования есть проблемы. ![]() Поподробнее пжлст. Только учти, что в бэкграунд воркере тот же, как ты выразился, "баг". Это плохой пример, потому что он -- частный. Если в каком-то редком случае метод нельзя переопределять, то это можно запретить отдельным ключевым словом. А по умолчанию переопределение должно быть разрешено.
Ну так подумай и выскажи свои соображения. Так ты что, не знаешь? Ещё раз. Я могу объяснить, зачем нужен private тем, кто им не пользовался, не привык и не знает, зачем он нужен. Потому что я пользовался, привык и знаю. Но, естественно, я не могу объяснить это тому, кто это и так знает, но собирается изображать, что не знает (ты) ![]() А с virtual -- другая ситуция. Я пришёл с Джавы и там никогда не пользовался затенением, не привык к этому и действительно не знаю, зачем оно нужно. Своими представлениями по опыту Си++ я уже поделился, и они мне кажутся неприменимыми в данном случае. А ты, вместо того, чтобы объяснить, или признаться, что сам не знаешь, просто аргументируешь на уровне раз большие дяди так сделали, значит это надо. Я про вред ничего не говорил. Я говорил про наиболее часто нужные вещи в работе. Добавлено через 7 минут и 17 секунд
Так это связано. Сперва (как я понял) аргументация была такая, мол, а почему бы и нет? Лозунг -- больше возможностей, плохих и хороших. Тогда я заметил, что невиртуальность сделана по умолчанию, то есть, трактуется не просто как одна из возможностей, а как важнейшая из них. Ведь если бы дело было только в том, чтобы предоставить ВОЗМОЖНОСТЬ делать невиртуальные функции, то можно было бы ввести слово "nonvirtual" и всё. А по умолчанию делать бы функции виртуальными.
Ну так как же можно помешать работе кухни с помощью виртуального метода? Я определяю класс и в нём создаю метод, который делает бред. Ну всё -- значит я создал дурацкий класс. Объекты этого класса будут дурацкими вне зависимости от того, переопределил ли я виртуальную функцию или просто с нуля написал функцию, которая бредит. Никаких проблем со связностью я тут не вижу. Никто ни с кем не связан. Есть просто сами по себе дурацкие объекты, и всё. Добавлено через 8 минут и 18 секунд Как это нельзя? А как же ключевое слово base? (Оно же super в Джаве). |
||||||||||||
|
|||||||||||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Хорошее слово. Жаль только за пределами класса использовать нельзя. -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Dims |
|
||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
Вот код:
вот вывод: Я невиртуальная в наследнике Я виртуальная в наследнике Я невиртуальная в базовом классе Я виртуальная в базовом классе Добавлено через 2 минуты и 40 секунд Вот такой код с теми же классами
даёт вот такой вывод: Я невиртуальная в базовом классе Я виртуальная в наследнике Добавлено через 4 минуты и 10 секунд То есть, чтобы вызвать невиртуальную функцию базового класса, нужно просто преобразовать тип. А виртуальную функцию базового класса вызвать нельзя, в этом и состоит защита: функция, написанная, когда производного класса ещё не было в природе, не имеет права с ним работать, если была переопределена. |
||||
|
|||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Та я ж писал об этом. Когда на кухне используется метод, от него ожидается, что он будет делать дело определённым образом, а когда его переопределяют, он может делать это и по-другому. Это приходится учитывать. Не всегда возможно, да и лишний код, затраты на проверку условий и т. д. Я создаю метод для каких-то внутренних целей а кто-то его переопределяет, он работает не так как я задумал. И что в результате должно получиться? А человек, занимающийся наследованием моего класса не будет понимать откуда проблемы. У него ведь не обязательно должны быть исходные коды. Поэтому и по-умолчанию. А наследование это не только переопределение методов, а вообще расширение функциональности класса, определение новых методов например. Поэтому я не понимаю, к чему разговоры о нормальном наследовании и ненормальном. Добавлено через 3 минуты и 33 секунды Правильно, а если надо иметь такую возможность, то она есть - не делать метод виртуальным. Так что же: лучше бы её не было что ли? -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Dims |
|
||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
Во-первых, внутренний метод будет private. А во-вторых, ну и что? Вред от этого будет только тому классу, который создан этим кем-то. И этот вред будет равен вреду от просто неправильно написанной функции. Но мы же не может надеяться запретить людям писать неправильные функции! Добавлено через 3 минуты и 56 секунд
Так я ж говорю, что если бы это была просто возможность, которая когда-то (непонятно, когда) может пригодиться, то тогда ладно. Но это не просто возможность, а возможность по умолчанию. То есть, важная возможность. Поэтому, её надо понять, не так ли? Это сообщение отредактировал(а) Dims - 3.11.2008, 21:56 |
||||
|
|||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Да, и кстати: затенение не является такой уж важной фичей. Это просто дополнительная возможность, своего рода компенсация того, что невиртуальные методы нельзя переопределить. Я уже писал, что затеняющий метод - это скорее перегрузка метода базового класса. На практике он почти не используется(поэтому и пример из практики привести трудно), но если это надо - то такая возможность есть.
Добавлено через 3 минуты и 4 секунды Да, но при этом он не будет знать в чём ошибка, так что лучше запретить. Та я то понимаю, только проблема в том, что мои аргументы мне кажутся убедительными, однако есть и другая точка зрения. -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Dims |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
Тогда почему она включается по умолчанию?
Я не понимаю. Из этого следует, что нужно вообще запретить виртуальные функции. Но Вы же не делаете такой вывод? Вы почему-то делаете вывод, что надо ПО УМОЛЧАНИЮ отключить. Но для такого вывода недостаточно одной лишь констатации вреда, нужно СРАВНИТЬ частоту вреда и пользы, и сделать по умолчанию то, что приносит больше пользы и меньше вреда. Добавлено через 4 минуты и 14 секунд Вот, например, вред от невиртуальной функции -- можно вызвать базовую функцию по отношению к производному классу. Вот ещё вред от невиртуальной функции -- невозможно вмешаться переопределить то, чего не предусмотрел или забыл предусмотреть разработчик базового класса. Кстати. Я тут покопался, и прихожу к выводу, что это и есть основной мотив. Микрософт, как коммерческий разработчик, заинтересован в том, чтобы его классы можно было использовать только так, как он предусмотрел. То есть, получать только то, за что заплачено. Если есть какая-то возможность развития класса, которую Микрософт не заметил и, стало быть, не взял за неё деньги при продаже, то эта возможность должна быть ограничена. |
|||
|
||||
diadiavova |
|
||||||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Потомучто альтернативой затенению является переопределение, а от него вреда может быть больше. Если человек включил в свой класс метод, не думая о том, что его метод будет вызван базовым классом, а он всё равно будет вызван - это может стать проблемой. Поэтому по-умолчанию.
А такой вывод я не делаю по двум причинам: 1.Знаю для чего нужны виртуальные методы. 2.Я уже миновал тот возраст, которому свойственен максимализм. Поэтому придерживаюсь средней линии. Вместо "всё или ничего" я предпочитаю "всё хорошо в меру и ко времени" Я так понимаю, что возможность вреда уже не оспаривается. О частоте вообще можно спорить долго, честно говоря не представляю себе как эту самую частоту вообще можно исчислить. Если речь идёт о неопытном программисте, то ему вообще запретить надо почти всё, а супердуперпрофи может не париться, у него и так всё получится. Я тут недавно одному парню советы давал по прорисовке в форме, так он в таком удивлении был, когда я объяснил ему, что надо вызвать Invalidate при изменении параметров прорисовки. Ему и в голову не пришло, что методы бывают виртуальными, и что метод определённый в базовом классе может вызывать прорисовку, которую он сам настряпал. Добавлено через 5 минут и 33 секунды
А можно и не вызвать, а вслучае с виртуальной - выбора нет. Иногда это хорошо, а иногда - плохо.
Если разработчик создал плохой класс(по забывчивости), не лучше ли использовать другие разработки(кто его знает, что он там ещё забыл) Коммерческий разработчик - не только майкрософт, а возможность такая есть не только у встроенных классов. -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
||||||
|
|||||||
PashaPash |
|
||||||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
Вот основная мысль:
Я за 6 лет сидения на C# использовал затенение ровно 0 раз. Поэтому ответ - незачем. Нужно не извращаться с затенением, а продумывать интерфейс базового класса. Кому должно? Вот лично мой опыт показывает, что действительно виртуальные функции - те, которые можно переопределить, и те которые действительно можно переопределить без знания о внутренностях базового класса встречаются очень-очень редко. Вообще, сам факт наследования (не от базовых классов FCL) встречается очень редко. В основном из-за того что:
C-ШАРП, раз уж ты на нем пишешь. У наследования есть проблемы вообще в OOP/OOD.
Выше был пример. Твой воркер налагает ограничения по функциональности на наследников. Это серьезный баг с точки зрения дизайна - для того, чтобы создать простого наследника, кто-то должен будет перечитать документацию по всем методам воркера - потому что там наверняка можно будет встретить "если вы переопределяете А, то вы должны переопределить В, который обязательно должен вызвать С до вызова D, и ждать пока E станет false". Честно, не знаю ;) Потому что твои аргументы применимы и к private. Типа, если написал код, который вызывает public функцию, и что-то не работает - то это код дурацкий. Никто не сколняет тебя к затенению, даже наоборот. НИКОГДА не используй его. Я аргументирую на уровне "я наступал на грабли, я знаю зачем невиртуальные функции". Просто ты не можешь понять решения проблемы т.к. с ней не сталкивался. Вообще есть 2 проблемы, но ты из сливаешь в одну: 1. Невиртуальность по умолчанию. Это есть гуд. Хочешь доказать что не гуд - напиши версию воркера, которая не будет требовать сакральных требований. 2. Возможность делать затенение. Из 1 никак не следует что все поголовно затеняют методы. Из 1 следует только то, что интерфейс будет состоять только из тех методов, для которых возможность переопределения продумана. Как ты из этого выводишь что все поголовно затеняют вместо использования virual - я просто не понимаю. А если знаний об интерфейсе класса недостаточно, чтобы написать рабочий вариант, как в случае твоего воркера? Документация - это зашибись, вот только ее очень часто не читают, или читают неправильно. Или забывают писать ![]() Добавлено через 5 минут и 57 секунд она выключена по умолчанию, надо ее включить словом new. прочитав предварительно сообщение о возможных последствиях. По умолчанию приносит меньше вреда невиртуальная функция и ругательства при попытке затенить. Отличная гипотеза, вот только .net бесплатный и с открытыми исходниками. А вот в этом: "только так, как он предусмотрел" заинтересован каждый разработчик, потому что если упал твой код, пусть даже из-за кривого наследника, но глубоко в твоем коде, то виноват только ты. Все отмазки типа "это наследник кривой", "он унаследовался неправильно" не прнимаются ![]() |
||||||
|
|||||||
Dims |
|
||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
Я этого не вижу. Отсутствует логический переход. Из одного описания гипотетического вреда делается вывод, для которого необходимо сравнение вреда и пользы с разных сторон.
Ну так невиртуальность в Си-диез используется безо всякой меры. Максималистски. Она никогда и не оспаривалась. Вред может быть ото всего. Но я хотел оценить этот вред, для чего просил привести примеры.
Ну грубо можно: если несколько человек несколько дней не могут вспомнить подходящего случая, то частота невысока. И заведомо ниже, чем то, для чего следует использовать умолчание. А это, кстати, ещё один пример вреда от умолчательной невиртуальности: люди привыкают к ситуации, которая ненормальна. И о нормальных вещах узнают с удивлением. Здесь под "нормальным" я понимаю то, что чаще пригождается. Польза от виртуальности нам известна, а вред от неё пока что гипотетичен. Сюда же я кладу многолетний опыт программирования на Джава: ни разу виртуальность не принесла вреда, зато постоянно исПОЛЬЗовалась. Только когда я перешёл с Си++ на Джаву, я и узнал, что такое настоящее ООП во всей красе. Добавлено через 2 минуты и 21 секунду
Это не плохой класс, а базовый. Предназначенный к расширению. Причём все возможности расширения предусмотреть должно быть невозможно. Потому что, если бы их можно было предусмотреть, то можно было бы включить в класс. |
||||||||
|
|||||||||
Dims |
|
||||||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
Ты уже написал об этом разработчикам бэкграунд-воркера в Микрософт? У них точно такие же требования. Ну. Значит твой опыт так же говорит, что это не нужно. Тогда о чём мы спорим? Почему ты продолжаешь отрицать, что это ошибка разработчиков? Очень-очень редко -- это всё-таки чаще, чем 0, который ты признал по затенению. А си-плюс-плюс ты называешь си-плас-плас? ![]() А почему тогда такой баг допустили в Майкрософте?
Это слова. А язык говорит другое: ВСЕГДА используй затенение.
Ну так расскажи же о ней поскорее! Что ты тянешь так долго? Готовишь морально? ![]()
Не вижу связи. Мой воркер содержит требования, аналогичные требованиям которые только что тут были описаны насчёт Validate и аналогичные требованиям, которые выдвинуты для Микрософтовского воркера. Ты предлагаешь мне для доказательства своей позиции превзойти в программировании всех на свете? А пониже планку никак не судьба? То же самое относится и к виртуальности. Из виртуальности метода не следует, что все поголовно его переопределяют. Поэтому здесь 0:0 или 1:1. Ничья. Изъян твоей позиции в том, что ты никак не хочешь СРАВНИВАТЬ. Ты просто говоришь о висящих в воздухе вреде и пользе, об каких-то недостатках одного подхода. А надо говорить о РАЗНИЦЕ.
Если недостаточно знаний об интерфейсе автомобиля, то как на нём ездить? Вот ты знаешь, что у автомобиля есть руль и он круглый и его можно крутить, и что есть педали и их можно нажимать. Но не знаешь, что они делают. Ответ: никак. Чтобы объектом пользоваться, надо знать не только тип параметров его интерфейса, но и что они делают.
new это варнинг. Его можно и не ставить.
Ругательств при переопределении тоже больше -- забыть override это ошибка, а не замечание. "Кабы чё не вышло и чёб на меня не подумали" это не единственный мотив. Есть ещё такое понятие, как расширяемость. Каждый разработчик заинтересован и в ней тоже, причём даже больше, чем в первом. |
||||||||||||
|
|||||||||||||
Partizan |
|
|||
![]() Let's do some .NET ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2828 Регистрация: 19.12.2005 Где: Санкт-Петербург Репутация: 18 Всего: 67 |
![]() Уж чего-чего, этого точно никто не говорил.... P.S. Лучше бы вы человеку про затенение не говорили...ему было бы спокойнее. -------------------- СУВ, Partizan. |
|||
|
||||
diadiavova |
|
||||||||||||||||||||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Здравая мысль! Если невозможно предусмотреть всего, значит невозможно основывать на этом какую-то логику. А если метод всё-таки нужен, то его надо делать private, а если в классах-наследниках такой метод тоже понадобится, то его по всей видимости прийдётся продублировать(потомучто private там не видно). И тут мы вообще приходим к абсурдной ситуации у нас окажется два одинаковых метода, один из которых мы сделаем private (внутренняя кухня), а второй будет виртуальным, хотя из базового класса мы его вызывать не будем.
Ну почему гипотетического? Если я создаю метод, и не имею возможности знать что от него можно ожидать, а что нельзя, то как я должен работать с ним? Обычно при вызове метода я ожидаю от него конкретного результата, а как я должен вызывать метод если понятия не имею, что он будет делать? А то, что при определённом опыте можно обходить неудобства, ещё не говорит о том, что неудобств этих нет. И если в яве, где все функции виртуальны люди чувствуют себя комфортно, так и на ассемблере до сих пор некоторые пишут.
Говоря о максимализме я отвечал на вопрос "Из этого следует, что нужно вообще запретить виртуальные функции...". Максимализм в том, чтобы отказаться от одного в пользу другого, а средняя линия - использование всего в меру.
Любой пример можно назвать частным случаем, а если он будет придуман для иллюстрации - надуманным. А какой случай нужен? Как я создал виртуальный метод, а его переопределение принесло вред? Так не помню я такого случая. Я же на яве не писал, а в дотнете виртуальные методы я создаю только когда в виртуальности есть потребность. Я просто не задумывался о том, как бы так создать виртуальный метод, чтобы от этого были проблемы. Поэтому всё что могу - это описать гипотетическую ситуацию, но полагаю - это слабый аргуумент.
Я думаю, что ява-прогеры о понятии виртуальности узнают тоже не в первый день. Создают виртуальные функции и понятия не имеют, что они виртуальны.
Норма - понятие очень обтекаемое. То, что норма в одном контексте - в другой может не вписаться даже на правах аномалии. А чаще пригождается программисту то, к чему он больше привык. Помимо правил и гайдлайнов всевозможных есть ещё индивидуальный стиль программирования(почерк), и вырабатывается он под влиянием того, с чем приходится работать. Не удивительно, что после явы некоторые вещи кажутся неудобными, но при другом стиле программирования как раз ява может показаться "не в масть".
Слегка напоминает высказывания последователей различных культов "Только познав Господа я ощутил всю полноту жизни" ![]() Ничего не имею против религии, только мы о программировании сейчас. А ООП это просто набор принципов, которые могут реализовываться по-разному, и принадлежность к ООП накладывает не так много ограничений на язык как некоторые думают.
Не ошибка, а возможность, которая жрать не просит, а если кому надо - пусть берёт, не жалко.
Я как-то чего-то затенял, но потом общая идея оказалась неудачной, пришлось всё поменять, и в новом варианте затенения не было. Но неудачной идея была не из-за затенения, там что-то другое вылезло(уже не помню) Кстати почему-то некоторых действительно раздражает. Я тут C# до-диезом называл, так один человек даже в подписи призвал так не поступать, хотя это как раз логичное название. Если американцу сказать си-шарп, то он скорее всего подумает, что речь идёт о ноте, а что до обозначения C#, так это вообще общепринятое обозначение ноты до-диез, и появилось оно задолго до компьютеров.
Проблема в том, что переопределение нужно в тех же случаях, что и затенение. Когда требуется собственная реализация метода с определённой сигнатурой. Но если эта реализация нарушит работу базового класса можно использовать затенение. Редкость его использования происходит от того, что классы проектируются таким образом, чтобы затенение не требовалось. Это вообще случай исключительный, а про умолчание повторяться не буду. Добавлено через 5 минут и 23 секунды
А кто знал, что дополнительные возможности могут кого-то расстроить. Я если спрашиваю про какие-то особенности, то только из соображений, что возможно я что-то упускаю. Но вопросов такого типа у меня не возникает... Добавлено через 12 минут и 35 секунд Кстати здесь поблизости ещё одна такя же тема обсуждается. Там речь идёт о грядущих возможностях си-шарпа(исправляюсь ![]() -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
||||||||||||||||||||
|
|||||||||||||||||||||
Dims |
|
||||||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
А причём тут виртуальность? Поверьте, тысячи людей используют Джава, где все методы виртуальные, и они отнюдь не находятся в описываемом Вами положении ![]()
Ну это если мы исходим из злонамеренности собеседника.
Ну так а как же Вы можете быть уверены, что такие случаи существуют?
Я не против. Объясните, каким образом невиртуальные функции являются нормой вместе с контекстом, который тоже объясните.
Это не ко мне. Я не делаю культа ни из чего. Или делаю из всего, то есть, пытаюсь найти логику и привлекательность в разных вещах.
Ну вот. Итак, трое (включая меня) признают, что затенение не нужно. Отсюда вывод, что с нашей (конечно, субъективной и, возможно, ошибочной) точки зрения, разработчики Си-диеза допустили ошибку, когда включили его по умолчанию. Я думаю, они просто не знают, что такое диез, и как это будет по-английски. Логика совершенно ясна: в названии Си++ использовали оператор ++ из Си, чтобы обозначить язык больше Си, а в названии C# использовали уже музыкальный оператор повышения тона, то есть, диез; чтобы обозначить то же самое. |
||||||||||||
|
|||||||||||||
Partizan |
|
|||
![]() Let's do some .NET ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2828 Регистрация: 19.12.2005 Где: Санкт-Петербург Репутация: 18 Всего: 67 |
Я думаю, что они знают, что такое диез... Всего-навсего так уж повелось, что язык программирования С# программисты(по крайней мере абсолютное большинство) называют "Си-шарп", в то же время музыканты запись С# в нотном стане, очевидно, прочтут как "до-диез"...и это тоже нормально, ибо в музыкальной области это действительно обозначение ноты... -------------------- СУВ, Partizan. |
|||
|
||||
PashaPash |
|
||||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
У них требования не к наследнику, а к обработчику. Человек, подписавшийся на событие с гораздо большей вероятностью прочтет документацию по этому конкретному событию, чем по всем методам класса. Небольшая такая разница, из-за которой не нужно читать полную документацию по 20 методам майкросовтовского воркера.
Вообще спорим о том, что ты считаешь что warning - это предупреждение. На самом деле warning - это самая настоящая ошибка. Ну уж никак не До-крест-крест. Если на стене висит ружье, то оно выстрелит. Если что-то можно сделать неправильно, кто-то сделает это неправильно. 1:0. Твой аргумент? Что не есть как. Ты ездишь на автомобиле, все классно, но через год к тебе приходят и говорят: тут надо после каждого километра хреновинку поворачивать на полоборота? вы не поворачивали? ну тогда придется автомобиль выбросить и купить новый. Да, и штраф заплатить по количеству непроворотов. "как бы не пришлось учитывать что есть чужая кривая реализация" - тоже неплохой мотив. А ты предлагаешь по принципу: параметры валидируют только трусы! Разработчик заинтересован в контролируемой расширяемости, а не в поддержке чужих расширений. |
||||
|
|||||
diadiavova |
|
||||||||||||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Не только верю, но и сам думаю, что так оно и есть. Это привычка, выработашаяся при написании программ на яве. Я уже упоминал, что вещи неудобные в принципе могут казаться единственными удобными тем людям, которые к ним привыкли. Я исхожу не из злонамеренности, а из того, что вижу в собеседнике вполне естественное желание отстоять свою точку зрения. Просто иногда это желание ЗАТЕНЯЕТ желание разобраться в вопросе. Типичный пример плохого затенения.
Ну у меня есть оправдание. Корпорация майкрософт надёжно защитила меня от таких ошибок. ![]()
Да контекст я ка бы уже объяснял. Ну вот пример: внутри класса я создаю метод, возвращающий строку в определённом формате. Вызывая функцию я ожидаю, что она будет возвращать нужную строку и её обработка не потребует много усилий. Если же я даю возможность переопределить метод, то строка может быть какой угодно. Мне потребуется проверить корректность строки, очень желательно, расширить формат, потомучто лишний пробел может сделать строку нечитабельной, и предусмотреть действия, при некорректном результате, которого в случае с моей функцией просто не может возникнуть. Теперь вопрос: какой вариант функции проще и безопаснее описать? Я этого не утверждал. Трудно рассуждать о примере, сути которого даже я не помню(разве что примерно помню что делал). Затенение там было нужно и проблему создало не оно. Я тогда осваивал элементы управления и делал комбобокс с картинками. Мне надо было чтобы элементы, которые принимает коллекция Items были строго моего типа, который содержал информацию о картинке, её расположении и т. д. Но свойство Item(а в бейсике индексаторы считаются свойствами) не было виртуальным и я его затенял. В данном контексте действие вполне уместное, но сама идея как оказалось не очень.
Насчёт большинства - сомневаюсь, компьютерщики всех мастей вообще любят называть то с чем работают всякими смешными словами.
Вряд ли в нотном стане может появится такая запись(разве что при обозначении аккорда или тональности)
А почему сосно музыкант не может быть программистом? Добавлено @ 00:45 Да насчёт автомобиля совсем забыл. Для тог, чтобы ездить не надо знать устройство. Надо просто уметь пользоваться интерфейсом. Это сообщение отредактировал(а) diadiavova - 4.11.2008, 00:47 -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
||||||||||||
|
|||||||||||||
Partizan |
|
||||
![]() Let's do some .NET ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2828 Регистрация: 19.12.2005 Где: Санкт-Петербург Репутация: 18 Всего: 67 |
diadiavova,
Ну зачем ёрничать...
Я говорю об области, в которой используется обозначение... ежели это название языка программирования, то правильно будет его называть именно так, как устоялось...а именно "си-шарп" ежели это музыкальное обозначение и мы говорим о музыке, то пожалуйста... тогда говорим "до диез" ....кстати говоря в этой теме я вообще увидел ещё одно))) Си-диез ) это у нас что?...я слышал, что у ноты Си диеза нету, только бемоль ) -------------------- СУВ, Partizan. |
||||
|
|||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Вообще-то ёрничаю я совсем не так. По моему это уже можно было заметить. Примеры могу привести на ходу мускул пхп хтмл васик жаба(по-моему куда более обидное название) И это только языки программирования. А рассуждать обо всяких имхо, сабжах, матерях(в смысле железа, вот ещё тоже словечко "железо") можно вообще до бесконечности. Ну о том как сленг приходит из других областей тоже можно рассуждать долго.
Здесь просто было название буквы(а точнее языка си) соединено с названием значка в русском языке, а музыкальный термин вообще не имелся ввиду. А си-диез есть, только это чистая до. Просто между си и до - полтона, поэтому повышение си на полтона (это делает диез) приводит к ноте до.(это так, если интересно) -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Partizan |
|
|||
![]() Let's do some .NET ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2828 Регистрация: 19.12.2005 Где: Санкт-Петербург Репутация: 18 Всего: 67 |
Ладно )
Не хотите обращаться в нашу веру? - Как хотите ![]()
всё это производные от написания/произношения... Си-Шарп вполне попадает в этот ряд... никто же не говорит "МойЭсКуЭл" Это сообщение отредактировал(а) Partizan - 4.11.2008, 01:23 -------------------- СУВ, Partizan. |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Та я ж из васиков. И кстати, уверен, что васик - круче.
Добавлено через 4 минуты и 3 секунды А просто потому, что давая сленговые имена, думают не о логике, а о том, чтобы прикольнее было. -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Partizan |
|
|||
![]() Let's do some .NET ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2828 Регистрация: 19.12.2005 Где: Санкт-Петербург Репутация: 18 Всего: 67 |
diadiavova,
о логике:
Во всех статьях говорится именно о # как о подчёркивании сходства с С++, но нигде не говорится, что символ # был использован, чтобы показать "превосходство на полтона" ) -------------------- СУВ, Partizan. |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Я видел оба варианта объяснения, и кстати: о последнем узнал недавно. В любом случае всё это только предположения. Официальных разъяснений на этот счёт я не видел, да и потом, о логике: повторюсь
Это сообщение отредактировал(а) diadiavova - 4.11.2008, 01:35 -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Partizan |
|
|||
![]() Let's do some .NET ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2828 Регистрация: 19.12.2005 Где: Санкт-Петербург Репутация: 18 Всего: 67 |
diadiavova, надо будет написать Хейльсбергу и спросить у него )))
-------------------- СУВ, Partizan. |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Это сообщение отредактировал(а) diadiavova - 4.11.2008, 02:06 -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Partizan |
|
|||
![]() Let's do some .NET ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2828 Регистрация: 19.12.2005 Где: Санкт-Петербург Репутация: 18 Всего: 67 |
Как минимум интересно...
-------------------- СУВ, Partizan. |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
А вот кстати:
Язык F# - фа-диез И что после этого думать? -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Partizan |
|
|||
![]() Let's do some .NET ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2828 Регистрация: 19.12.2005 Где: Санкт-Петербург Репутация: 18 Всего: 67 |
diadiavova, J# тогда это что?
-------------------- СУВ, Partizan. |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Ява Свою реализацию javascript они назвали jscript, логично, что, стырив яву, они придерживались той же логики. А диез добавили, чтобы показать, что их ява круче ![]() Добавлено через 2 минуты и 16 секунд Кроме того, имя было неправильное, поэтому язык долго не прожил Добавлено через 4 минуты и 27 секунд И кстати: если C# выше С на пол-тона, то F# - выше C# на целую кварту. -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Partizan |
|
|||
![]() Let's do some .NET ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2828 Регистрация: 19.12.2005 Где: Санкт-Петербург Репутация: 18 Всего: 67 |
Не...я в смысле - это у нас чтоли Соль-диез?...
Не...не правильно это, язык программирования называть музыкальным термином...надо разграничивать... з.ы. ладно...это уже полный оффтопик... по топику могу только сказать, что согласен с теми, кто утверждает, что виртуальные по умолчанию методы из джавы(явы, как угодно) кроют потенциальную опасность, и, поэтому, невиртуальность по умолчанию, как это сделано в C# является плюсом... -------------------- СУВ, Partizan. |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Соль-диез будет G#. Не удивлюсь если и такой язык появится. Трудно говорить, о таких вещах, как о плюсах или минусах. Дело привычки. Просто можно было какое нибудь ключевое слово придумать для всего класса, которое меняло бы умолчания, здесь варианты есть, да кто знает - может и придумают что-то в этом роде. -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Dims |
|
||||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
На мой взгляд, музыканты ни причём. Даже американские немузыканты воспринимают название языка как "Си-диез". Они могут не знать, что "Си" означает ещё и ноту, а думать, что речь идёт о языке Си. Добавлено через 8 минут и 58 секунд Это что, существенно меняет дело? Требования те же самые, один х... надо читать инструкцию. Твой идеальный мир, в котором этого можно не делать всё равно не прорисовывается.
Это уже чистейшая инстинуация с твоей стороны. Требования те же самые, элементы те же самые, предназначение то же самое, значит и вероятность прочесть инструкцию та же самая.
От того, что ты это сказал, оно так не стало ![]()
Я не понял, почему это ты себе очко записал? Это абстрактное рассуждение с тем же успехом можно записать и на мой счёт. А я где-то утверждал, что что есть как?
Разработчик железобетона предназначал его для изготовления цветочных горшков. Прикинь, что бы мы сейчас делали, если бы у него был в распоряжении C# для реальности? Добавлено через 13 минут и 58 секунд Это говорится в англо-русском словаре, в статье про слово "шарп", которое переводится, как "диез". Странно, что они говорят "си-шарп", но не имеют в виду диез, потому что тогда почему они говорят именно так? |
||||||||||
|
|||||||||||
Dims |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
Ну это претензия к Микрософту. Добавлено через 1 минуту и 32 секунды http://en.wikipedia.org/wiki/C_Sharp_(prog...)#Language_name |
|||
|
||||
PashaPash |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
Нет, не те же. Для наследования от твоего воркера надо прочитать документацию по всем его функциям. Для использования MS-ового - только требования к обработчику события. Ты разницу между 1 статьей и полной документацией чувствуешь? Для дизайна MS не нужны виртуальные по умолчанию функции, даже наследование не нужно. Для твоего - надо обязательно сделать новый класс, и изучить всю документацию по базовому классу. Есть галочка threat warning as errors. Которую принято включать ![]()
Наследование и виртуальные функции - не единственный способ расширяемости. Вообще, наследование не от классов фреймворка - очень редко используемая вещь. Возьми, например, среднее web-приложение. Плоская иерархия классов-страниц, плоская иерархия контроллеров, плоская иерархия сервисов в BL, плоская иерархия объектов домена. Куча невирутальных функций. Основной упор - на реализацию интерфейсов, чтобы IoC работал. В win - та же самая картина. 90% классов не объявляют новые виртуальные функции и не переопределяют существующие. И вроде никто на проблемы с расширяемостью не жалуется. Нужно еще классы сделать sealed по умолчанию - потому что при написании классов никто обычно не думает что будет при наследовании. Очень сомневаюсь, что ты всегда думаешь о последствиях override-а. Ты утверждал что практически любой метод можно сделать виртуальным без последствий. Это подразумевает что создающий наследника знает что делает метод родителя, и как именно он это делает. Или всегда может корректно переопределить его без знаний о деталях реализации этого метода в родителях. Т.к. телепаты пока не появились, то скорее - первое. Это сообщение отредактировал(а) PashaPash - 4.11.2008, 11:13 |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
В Америке существует два способа именования нот. Одно - международное(как у нас), оно почти не используется; другое происходит от английского названия латинских букв, которыми принято обозначать ноты(за одним небольшим исключением, происходящим от того, что американская система немного отличается от классической, это касается нот си и си-бемоль). Поэтому если сказать американцу си-шарп, он скорее всего подумает, что речь идёт именно о ноте. А статья порадовала. Оказывется есть ест ещё язык A#. То есть семейство "музыкальных" языков пополнилось ещё и ля-диезом ![]() ![]() Это сообщение отредактировал(а) diadiavova - 4.11.2008, 13:27 -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Dims |
|
||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
Эту разницу ты создал. Обработчик события DoWork -- это то, что у меня абстрактный метод SpecificWork. Собираясь его реализовать в наследнике, я должен буду прочесть к нему инструкцию. И там увижу почти тот же текст, что и в инструкции к Микрософтовскому воркеру. В частности, у себя в инструкции я увижу, что нужно проверять ShouldStop, а у Микрософта, что нужно проверять CancellationPending. Точно так же, как у Микрософта я могу захотеть написать обработчик RunWorkerCompleted и тогда прочту к нему инструкцию, так же и у меня я могу захотеть реализовать Done и тогда прочту инструкцию к нему. Короче, те же яйца, вид сбоку. Где ты там видишь какую-то разницу, ума не приложу.
Выдумываешь.
Это не голословное утверждение, а вывод на основе опыта программирования на Джава. Сообщество накопило, наверное, миллионы человеко-часов. Ты понимаешь, поэтому, что все жутчайшие выводы, которые ты сейчас сделаешь -- это борьба с ветряными мельницами? Я же предлагаю рассуждать разумно. Если виртуальность всех функций и содержит какие-то недостатки, то они ТОНКИЕ. Нет такого, как пишешь ты. Или как diadiavova написал, что он не любит работать, когда сидишь и не знаешь, что делают методы, мол, якобы, это следует из виртуальности. Не так это. Не следует. |
||||
|
|||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Я не писал, что не люблю. А что следует из виртуальности, если не то, что в производном классе функция будет делать неизвестно что? =============== Тут мне ещё вот какая мысля пришла в голову. Ну ладно, если мы пишем абстрактный класс. В нём по-идее сильно завязывать одно на другом - плохо, и надо сводить такие зависимости к минимуму. Но ведь наследуются не только абстрактные классы. Я могу писать класс под определённые нужды. В нём естественно я и не очень расчитываю на то, что что-то будет переопределено, но возможность такую оставляю, на случай если кому-то надо будет расширить мой класс. В такой ситуации по-моему вполне естественно что я предоставляю потенциальному(!) наследователю доступ только к тем элементам, которые расчитаны на то, что их могут переопределить. Всё остальное нужно для работы моего класса. Кроме того: спорить о том, надо докуметировать классы или нет - бессмысленно. Другой вопрос: что лучше класс, требующий минимума документации, или такой, где про каждый метод надо будет объяснить все возможные последствия того или иного действия? Покупая телевизор тоже инструкцию надо прочитать, но совсем не обязательно знать как он устроен для того, чтобы каналы переключать. Поэтому и возникает вопрос, что лучше сделать максимально безопасный класс, или позволить делать с ним всё, но снабдить подробной инструкцией, объясняющей, почему этого делать нельзя. -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
Dims |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
Я же говорю: этот вывод элементарно опровергается практикой. Не могло бы быть на джаве написано столько качественных прог, если бы функции делали неизвестно-что. |
|||
|
||||
PashaPash |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
Что, не надо создавать базовый класс? Или не надо читать документацию? Ок, используем подход java и делаем все методы виртуальными. Их в воркере штук 7, если считать сеттери и геттеры. Сколько из них может полностью переопределить наследник, не поломав всю реализацию? Полностью - без вызова base и без дублирования кода из base. Только 2, и то только потому что они ничего не делают. И виноват в этом ес-но ... автор наследника. IMHO, виноват автор базового класса, который не продумал интерфейс. А теперь сравни это с возможностью неправильно подписаться на событие стандартного воркера. Он, кстати, не предьявляет вообще никаких требований к использующему его. Только надежда что тот будет периодически (да хоть раз в сутки) проверять CancellationPending. Что, совсем не видно разницы? А ведь именно из-за этой "неуловимой" разницы появился Design By Contract и прочие формы отказа от наследования реализации. Вот, линк по теме, а то пересказывать влом: http://blogs.gotdotnet.ru/personal/bezzus/...2c-f54450aa64d6 Есть PHP, в котором ООП в зачаточном состоянии. На нем написны миллиарды строк кода и проведены миллиарды человекочасов. На основе опыта программирования на PHP любой студент-кодер может сделать неголословное утверждение, даже вывод, что ООП - вообще вредно, только лишний раз мозг напрягает. Строгая типизация, обработка исключений, сборщик мусора, и вообще все, что хоть сколько-нибудь заботится о дизайне приложения, о минимизации контрактов, о соблюдении принципов ООП - это тоже борьба с ветряными мельницами? Или может это обдуманные решения, принятые ради удобства самих разработчиков? Миллионы леммингов не могут ошибаться. И, кстати, C#/.NET тоже довольно распространенные языки, но за все время я только один раз видел жалобы на невиртуальные по умолчанию функции. Вот в этом топике ![]() Добавлено через 4 минуты и 34 секунды
Зато на написание и на поддержку этого качества могло бы уйти намного меньше времени. |
|||
|
||||
Dims |
|
||||||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1016 Регистрация: 21.11.2006 Репутация: 0 Всего: 11 |
Да сколько угодно. Вопрос только, нафига их ему переопределять? Есть абстрактные методы, их переопрелять обязательно. А неабстрактные методы можно не переопределять. Ну ты придумай ещё каких-нибудь ограничений. А потом ещё какие-нибудь выводы сделай на основании того, что сам придумал.
Зачем мне сравнивать с возможностью подписаться неправильно? Не видно разницы в необходимом объёме прочтения документации и в объёме требований к, которую ты заявлял. Ты теперь признаёшь, что был в этом неправ и переходишь к рассмотрению какой-то другой разницы? Невозможно же, не разобравшись с одним вопросом, перескакивать на следующий.
А не надо пересказывать, надо высказывать свои мысли.
Не надо передёргивать. На основании этого опыта можно сделать вывод, что отсутствие ООП это не катастрофа, вот и всё. Ну если кто-то скажет, что без сборщика мусора -- полный капец -- то это будет борьба с ветряными мельницами. На самом деле, перечисленные тобой вещи просто улучшают жизнь, повышают КПД и производительность труда. Но они не превращают смерть в жизнь.
Конечно, это обдуманные решения. Дело не в количестве леммингов, а в качестве мыслей. За каждым решением должна стоять мысль, а эту мысль должно быть можно сформулировать. За отказом от виртуальных функций я пока увидел только одну мысль -- ограничить возможность наследника вмешиваться в функционирование того, что он использует в своей конструкции. Я нахожу это не плюсом, а минусом.
Ой, а покажи, на какой странице? И кто жаловался, не подскажешь? |
||||||||||||
|
|||||||||||||
Partizan |
|
|||
![]() Let's do some .NET ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 2828 Регистрация: 19.12.2005 Где: Санкт-Петербург Репутация: 18 Всего: 67 |
Dims, принцип наименьших привилегий знаком?
-------------------- СУВ, Partizan. |
|||
|
||||
PashaPash |
|
||||||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1233 Регистрация: 3.1.2008 Репутация: 13 Всего: 49 |
Это как раз не ограничения. Ограничения - это "обязательно надо вызвать base".
Так о том и спор. Если наследник не может корректно переопределить неабстрактный метод, то лучше бы этому методу вообще не быть виртуальным. А ты сходи, почитай. Может и появятся свои мысли, а не только "в java так, зачем вы сделали по-другому" ![]() Вообще-то объем документации которую НУЖНО изучить перед использованием класса напрямую связан с объемом требований. Просто ты почему-то воспрнимаешь, например, обязательный вызов base как само-собой разумеющееся, а не как требование, налагаемое на наследника. Или, например, необходимость поддерживать интерфейс следующих версий базового класса - тоже требование к наследнику.
Да любой пхп-ст тебе как два пальца докажет что ООП - бесполезный выверт. Недвано на хабре даже спор был о полезности ООП. Ну вот невиртуальность функций по умолчанию, и вообще переход от наследования реализации к наследованию контракта повышает производительность, КПД, и уменьшают количество багов и затрат на поддержку. Хочешь конкретных примеров - возьми стандартные паттерны - IoC/DI, MVC - не используется в них наследование. Возьми гамму - там наследование реализации очень редко встречается. Возьми того же Фаулера - там наследования почти нет. Возьми какой-нибудь Eiffel - типа идеал ООП - там вообще один интерфейсы. Почитай классику по ООП - Алана Кея - там нет наследования как такового. Вирутальные функции тоже не превращают жизнь в смерть, просто перед их объявлением надо думать. Ну не верю я, что до написания тела функции можно быть 100% уверенным в том, что она достойна стать виртуальной. А ты веришь в умных кодеров наследников, которые будут читать документацию. Мысль - ограничить возможность наследника вмешаться прямо (некорректно заменить) или косвенно (использовать недокументированные подробности реализации базового класса) вмешаться в реализацию базового класса. Снизить вероятность привязки наследника к конкретной реализации базового класса. Ограничить распространение изменений базового класса - отказом от наследования вообще, или от виртуальных функций в частности. Принудительно потребовать от наследника соблюдать принцип подстановки (а не на надеятся на умных кодеров наследника). И еще много мыслей, которые ты сейчас отметешь как несущественные, потому что в java можно кодить без них. Добавлено через 1 минуту и 6 секунд Partizan, бесполезно, он исповедует принцип свободы, и считает невиртуальные функции лишними ограничениями и происками MS. |
||||||
|
|||||||
mr.DUDA |
|
|||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
Модератор: БУУУУУУУУУУУ !!!!!!!!!!!!!
Ну народ, и нафлудили вы тут пока меня не было полгода... ![]() ![]() ![]() ![]() В общем, насчёт "почему все функции не виртуальные по умолчанию" отвечаю по существу. Потому что вызов виртуальной функции дороже с точки зрения производительности. Соответственно полиморфизм - необязательное свойство методов в сишарпе (в отличие от Java). -------------------- ![]() |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
На ассемблере тоже можно писать, некоторым даже не плохо это удаётся, это же не значит, что надо вернуться к ассемблеру. Я нигде не пытался доказать, что явовский подход неработоспособен. Просто тот, который реализован в дотнете мне кажется более удачным и безопасным. А кто говорит об отказе? Речь только о том, чтобы не делать виртуальными члены, не предназначенные для переопределения. -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
MasterOfCode |
|
|||
![]() elwin ![]() ![]() Профиль Группа: Участник Сообщений: 740 Регистрация: 24.4.2008 Где: World.Russia.Tyum en Репутация: 4 Всего: 27 |
OFF: Ура! Модератор вернулся. Теперь будет чистота и порядок. А то уже эти холивары надоели
![]() mr.DUDA: угу, дискуссия была весьма захватывающей, я даже попкорн купил... но для холиваров есть целый раздел, а тут им не место вообще-то. ![]() Это сообщение отредактировал(а) mr.DUDA - 6.11.2008, 00:43 -------------------- ![]() |
|||
|
||||
diadiavova |
|
||||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
То есть вот так вот значит, да? Развлёкся, попкорна похавал, а теперь мятыми упаковками от этого попкорна в тех, кто тебя развлекал швыряешь? И потом: причём тут холивар? Мы просто общаемся, выясняя вопрос, вполне вписывающийся в тематику форума. Если автор темы не пометил вопрос решённым - значит ему не всё ясно, а объяснения вроде
не убеждают даже меня, ибо в этом случае возникает вопрос: а почему тогда все классы не делаются завершёнными по-умолчанию? -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
||||
|
|||||
mr.DUDA |
|
|||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
Разницу между расширяемостью и оптимальным подходом видишь? Ну вот скажем, хочу я в одном случае сделать иерархию классов, с наследованием и полиморфизмом. На производительность мне начхать. Следовательно мне удобнее, чтобы классы были наследуемыми (а не завершёнными по умолчанию) и были доступны фичи а-ля реализация набора интерфейсов или базовых классов (как в С++), виртуальные функции и всяческий синтаксический сахар. Это про расширяемость. Теперь про оптимальный подход. Допустим я хардкорный программер и хочу поиметь максимальную производительность и мимимум оверхеда на всякие ООП-приблуды, но вынужден по той или иной причине пользоваться дотнетом и сишарпом. Что мне делать? Использовать один-два класса, функциональный подход, никаких виртуальных функций, структуры вместо классов на мелкие объекты, массивы через указатели и так далее. Здесь мне уже начхать на полиморфизм и наследование. Итак, вопрос: что важнее с точки зрения создателя такого языка и такой платформы как сишарп и дотнет? Ответ такой: важны все разработчики, важны все возможные области применения. Вердикт: минимум ограничений, максимум возможностей. Не запрещается наследование, но и не принуждается использование виртуальных функций. Пример частный, но в контексте темы. З.Ы. попкорном не кидаюсь!!!!! ![]() -------------------- ![]() |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Ну здесь, на сколько я понимаю, никто не говорил об ограничениях, спор всего-навсего о том, какими члены типов должны быть по-умолчанию. Умолчания обычно можно изменять, однако те значения, которые элементы имеют по-умолчанию, считаются оптимальными и наиболее часто используемыми. И разногласия были собственно в том, что чаще нужно: виртуальные члены или нет.
Если мне по тем или иным причинам понадобится виртуальный член, то скорее всего производительность отойдёт на второй план и я сделаю член типа виртуальным. Собственно, я говорил только о том, что в контексте разговора производительность(ИМХО) не является решающим фактором. Та ладно бы попкорном, а то пожамканая упаковка в ход идёт ![]() Это сообщение отредактировал(а) diadiavova - 7.11.2008, 02:51 -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
mr.DUDA |
|
|||
![]() 3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
diadiavova, работа такая у модератора - кидать упаковкой от попкорна или чем-нибудь потяжелее ![]() Консенсуса не видно, тема уже на 6 страницах, треть постов - оффтоп на тему нот и затенения. Заготавливаю ещё попкорн, чтобы было чем швыряться... -------------------- ![]() |
|||
|
||||
diadiavova |
|
|||
![]() Доктор Зло(диагност, настоящий, с лицензией и полномочиями) ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 5821 Регистрация: 14.8.2008 Где: В Коньфпольте Репутация: 31 Всего: 142 |
Можно было бы и попкорном швырнуть для разнообразия, а то тоже охота. Насчёт нот - согласен, а с затенения всё и началось. Dims спросил: зачем оно нужно, и тут выяснилось, что функции не виртуальные по-умолчанию. -------------------- Хочешь получить мудрый совет - читай подписи участников форумов. Злой доктор Щасзаболит ![]() |
|||
|
||||
![]() ![]() ![]() |
Прежде чем создать тему, посмотрите сюда: | |
|
Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов. Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :) Так же не забывайте отмечать свой вопрос решенным, если он таковым является :) Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |