C# скрытие методов
оракла на вас не хватает , шарпаебы
А мне объясните, пожалуйста, что значит скрытие методов
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class X1
{
public void test1
{
Console.WriteLine("xx");
}
}
class X2:X1
{
public new void test1
{
Console.WriteLine("xy");
}
}
class Program
{
static void Main(string[] args)
{
X2 test2 = new X2;
test2.test1;
X1 test1 = test2;
test1.test1;
Console.ReadKey;
}
}
}
это когда вот такой код выдает
xy
xx
вместо ожидаемых
xy
xy
т.е. то, какой метод вызовется зависит не от класса объекта, а от класса переменной.
ЗЫ: насчет терминологии - как в книжке написано, так я и написал, английского термина не знаю.
этож нарушение полиморфизмаХочешь полиморфизм — пиши virtual/override явно.
и от него становится код становится менее читабельным и понимаемым?В C++ поведение ровно такое же. Никто не жалуется.
Мне кажется, это наследие c++, когда иногда было очень важно, что метод НЕ виртуальный (соответственно, нет обращения к VMT и работает быстрее).
Другого use-case для невиртуальных методов я пока не могу придумать...
Чтобы задавать на собеседованиях коварные вопросы.
Хз, мне в этом видится дополнительная гибкость языка на случай, когда надо адаптировать (повторно использовать, скажем) классы из сторонней библиотеки и тебе нужны методы с теми же именами. Ну типа просто на всякий случай. А полиморфизм вот вообще не в тему. Т.е. писать-то так внутри собственного проекта наверное и не надо, но иметь возможность в экстренной ситуации так сделать наверное хотелось бы.
Так что невиртуальность методов по умолчанию — вполне правильный выбор с точки зрения эффективности.
C++ - недоязык, и все это знают.
ну раз в C# решили нагородить костылей ради совместимости с плюсами - пусть так и будет.
как раз если так и писать - то только _внутри_ проекта, чтобы никто извне не мог твоими классами воспользоваться, ибо начнется ахтунг, деление на 0 и конец света.
невиртуальность методов по умолчанию — вполне правильный выбор с точки зрения эффективности.ИМХО, с этой же самой точки зрения C# - не вполне правильный выбор языка Если нужна эффективность - надо писать на Си, разве нет?
как раз если так и писать - то только _внутри_ проекта, чтобы никто извне не мог твоими классами воспользоваться, ибо начнется ахтунг, деление на 0 и конец света.ничего не понял. Как невиртуальные методы помогут запретить пользоваться твоими классами?
Если можно не пессимизировать, лучше не пессимизировать. :-)
а так, что пользоваться переопределенными методами в унаследованных от твоих классах будет опасно, ибо неясно, когда будет вызываться твои методы, а когда - базового типа.
т.е. либо уж делать sealed, либо virtual.
а так, что пользоваться переопределенными методами в унаследованных от твоих классах будет опасно, ибо неясно, когда будет вызываться твои методы, а когда - базового типа.т.е. либо уж делать sealed, либо virtual.Ты сам ответил на свой вопрос. Для запрета наследования от твоих классов надо писать sealed. А невиртуальные методы тут не при чем.
а что тогда тут? хочешь невиртуального метода - пиши sealed, хочешь виртуального - пиши virtual. нахера нужна лишняя сущность, от которой я пока что вижу сплошные проблемы?
ЗЫ: в плюсах, насколько я помню, есть множественное наследование, поэтому там, возможно, подобное поведение имеет смысл.
а что тогда тут? хочешь невиртуального метода - пиши sealed, хочешь виртуального - пиши virtual. нахера нужна лишняя сущность, от которой я пока что вижу сплошные проблемы?Уже два предложения есть:
1) Невиртуальные методы эффективнее.
2) Нужно определить новый метод с той же сигнатурой, но совершенно другим поведением.
new нужен только на случай следующего сценария
в библиотеке есть класс A
от него унаследован свой класс B и в нем определен метод F
через некоторое время выходит новая версия класса A, в которой вдруг появился свой метод F, который никакого отношения к методу B.F не имеет.
и теперь чтобы не было путаницы метод F в классе B имеет смысл пометить new
ps
и соответственно new никакого отношения к виртуальности/невиртуальности или sealed не имеет.
>в библиотеке есть класс A
>от него унаследован свой класс B и в нем определен метод F
>через некоторое время выходит новая версия класса A, в которой вдруг появился свой метод F, который никакого отношения к методу B.F не имеет.
>и теперь чтобы не было путаницы метод F в классе B имеет смысл пометить new
ясно, спасибо.
>и соответственно new никакого отношения к виртуальности/невиртуальности или sealed не имеет.
это не ко мне, не я тут начал про виртуальность затирать.
Это нужно в основном при использовании библиотек сторонних разработчиков, если нет доступа к исходному коду. В случае конфликтов,всегда есть возможность переопределить реализацию метода базового класса.
чтобы понять "нахуя", как вы выразилсь, надо знать как внутри оно устроено.
в Х2 "старый" метод test1 никуда не девается. ты лишь заслоняешь его имя.
допустим ты можешь в Х2 определить метод test1_old и вызвать в нем унаследованный test1 родителя(Х1).
если заменять код, реализующий метод test1 полностью, такого не получится сделать.
а когда ты обращаешься к объекту Х2 через переменную типа Х1 у тебя просто вызывается этот "старый" код, который никуда не девался, как я уже говорил.
в делфи также есть заслонение и в яве (вроде) тоже.
И как это приближает нас к пониманию "нахуя"?
заслонение само по себе необходимо например для изменения сигнатур.
про заслонение написал выше.
чо-чо? и как мы скроем метод с другой сигнатурой?
по крайней мере я не встречал.
чо-чо? и как мы скроем метод с другой сигнатурой?не знаю как в шарпе, а в дельфях просто убираешь ключевое слово override и можно менять сигнатуру метода. я думаю в этом отношении они не сильно отличаются.
ну или ты под сигнатурой что-то своё, особенное, подразумеваешь.
Для этого же надо просто зайти в класс, ну и там добавить параметр функции или там имя ей изменить, вот тогда это будет «поменять сигнатуру».
Ну хз как там во всей этой схолистикой, но "старый" метод со старой сигнатурой в ребенке больше не будет виден.
не знаю как в шарпе, а в дельфях просто убираешь ключевое слово override и можно менять сигнатуру метода. я думаю в этом отношении они не сильно отличаются.Ты думаешь неправильно
В C# нет ключевого слова overload, и новый метод с тем же именем (но другими параметрами) не заслонит старый, а будет существовать наряду с ним.
И вообще, что за мода высказывать суждения о языке, которого не знаешь?
напиши мне псевдокод (ну или пример на дельфи, если уж совсем тяжко) изменения сигнатуры с get(int) на set(Object).
это лишь видимость скрытия
в любой момент его можно вызвать через X1)new X2.test1;
В C# нет ключевого слова overloadон говорил про слово override, которое в C# есть, но просто убрать его там нельзя, но можно заменить на new со схожими последствиями.
умные люди говорят что подобное желание свидетельствует о кривой архитектуре.
подобное желание свидетельствует о кривой архитектуре.мозга?
я вообще про делфи говорил, т.к. сишарп не знаю. (каюсь, отклонился от темы - сначала рассуждал про общие принципы ооп, а потом перешел на конкретный язык) просто они довольно похожи (сишарп и дельфи).
з.ы. в яве, насколько я помню, вообще вроде все методы виртуальные.
сигнатуру метода составляет его имя и последовательность типов параметровт.е. изменение типов параметров тоже является изменением сигнатуры.
или где?
ну да, а что тебя смущает?
насколько я тут понял, аналогом невиртуального метода в яве будет final, если у родителя метода с такой сигнатурой нет.
имхо ничего общего.
и в чем же разница?
В C# нет ключевого слова overloadЯ прекрасно понимаю, о чем он говорил, потому что писал 6 лет на Delphi и год на C#. Отличие у Delphi и C# в том, что по умолчанию в Delphi нет перегруженных методов: можно определить только один метод с данным именем. Если тебе хочется еще методов - изволь КАЖДЫЙ перегруженный метод пометить словом overload.
он говорил про слово override, которое в C# есть...
Соответственно, если у тебя был, скажем метод
type TParent = class
public:
procedure Init(path: String); virtual;
end;
А ты хочешь, чтобы в твоем наследнике Init принимал в качестве аргумента, скажем, TStringList, то надо написать:
type TChild = class (TParent)
public:
procedure Init(values: TStringList); reintroduce;
end;
При этом унаследованный Init будет "затерт" новым методом:
var
child: TChild;
...
child = TChild.Create;
child.Init('c:\config.txt');
вернет ошибку компиляции.
Ключевое слово reintroduce, как мне кажется, необязательное.
А, понял теперь
без reintroduce у тебя хинт вылезет, что ты заслонил/затенил (по англицки hide) виртуальный метод.
рассуждал про общие принципы ооп
Оставить комментарий
serega1604
может кто-нибудь популярно объяснить нахуя это сделано, особенно для интерфейсов?этож нарушение полиморфизма и от него становится код становится менее читабельным и понимаемым?