![]() |
|
Модераторы: Partizan, gambit |
![]()
|
|
| Elfet |
|
||||||||
![]() Белый и Пушистый ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 3776 Регистрация: 2.4.2003 Репутация: нет Всего: 16 |
Меня интересует в C# полиморфизм тоже самое , что и в С++?
В книжке приводиться вот такой пример:
Я не понимаю вот этот код:
Зачем здесь использовать полиморфизм? Точно такой же эффект будет если просто переопределить метод класса?
Как такое возможно? Это не всё равно что если сделать вот это? :
|
||||||||
|
|||||||||
| Ch0bits |
|
|||
![]() Python Dev. ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2124 Регистрация: 21.2.2005 Где: Казань Репутация: 9 Всего: 62 |
win = new ListBox(3,4,"text1"); - тут объект ListBox приводится к cвоему предку Window, а значит в цикле for будет вызван метод класса Window. Таким образом тут показано что любой дочерний тип можно привести к родительскому типу. Вот например:
|
|||
|
||||
| Elfet |
|
||||
![]() Белый и Пушистый ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 3776 Регистрация: 2.4.2003 Репутация: нет Всего: 16 |
Что-то не понял. Тут происходит неявное преобразование типов? Так если win являеться после win = new ListBox(3,4,"text1"); объектом класса Window, то с какой стати вызывать public override void DrawWindow()
Object O = M1 что происходит при таком действии? Если же не перегруженна операция преобразования типа? Это сообщение отредактировал(а) Elfet - 9.10.2006, 22:25 |
||||
|
|||||
| Ch0bits |
|
|||
![]() Python Dev. ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2124 Регистрация: 21.2.2005 Где: Казань Репутация: 9 Всего: 62 |
Этот метод не вызывается, т.к. является часть класс ListBox, который при создании сразу же приводится в предку Window. Добавлено @ 22:37
Ну этот как раз и есть проявление полиморфизма, что класс наследник имеет такой же интерфейс как и предок, только разную реализацию. Здесь показан обратный принцип. Это сообщение отредактировал(а) Ch0bits - 9.10.2006, 22:34 |
|||
|
||||
| Elfet |
|
|||
![]() Белый и Пушистый ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 3776 Регистрация: 2.4.2003 Репутация: нет Всего: 16 |
А каким способом он приводиться?
В книжке этим примером объяснялся полиморфизм и говорилось, что поскольку он объявлен ключевым словом virtual и производные классы переопределили его, то будет вызван DrawWindow() класса ListBox |
|||
|
||||
| Ch0bits |
|
|||
![]() Python Dev. ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2124 Регистрация: 21.2.2005 Где: Казань Репутация: 9 Всего: 62 |
Если в описании метода есть Virtual, то он считается виртуальным, т.е. ты можешь перекрыть его в классах наследниках.
Добавлено @ 22:53 Попробуй скомпилировать без Virtual, тогда получишь ошибку, потому что не виртуальные методы нельзя переопределять, их можно только заного объявлять через new. |
|||
|
||||
| Elfet |
|
|||
![]() Белый и Пушистый ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 3776 Регистрация: 2.4.2003 Репутация: нет Всего: 16 |
Не понял. перекрыть в классах наследниках - это как?
Если метод класса переопределён как виртуальная ф-ия, то в производном классе заменяеться не только метод, но и все вызовы его в дргих методах класса. Тут происходит позднее связывание через VMT? Добавлено @ 23:01
ТОгда зачем оно нужно вообще в этом примере? Если можно обойтись без virtual и override, а использовать new ? |
|||
|
||||
| Ch0bits |
|
|||
![]() Python Dev. ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2124 Регистрация: 21.2.2005 Где: Казань Репутация: 9 Всего: 62 |
Проще говоря, применять к методам класса родителя ключевое слово Override. Это плохой стиль. |
|||
|
||||
| Ch0bits |
|
|||
![]() Python Dev. ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2124 Регистрация: 21.2.2005 Где: Казань Репутация: 9 Всего: 62 |
new используют, когда хотят изменить прототип метода, например:
|
|||
|
||||
| mr.DUDA |
|
|||
|
3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
Elfet,
win не является объектом класса Window, а всего лишь ссылкой на объект класса Window или любого производного класса от Window (каким и является ListBox). Если знаком с С++, то можешь понять аналогию: принцип тот же, что и с указателями. Только в шарпе вместо указателей - ссылки. Присвоение переменной типа A значения типа B - то же самое что присвоение указателю A* значения из указателя B* (только для ссылочных типов, какими и являются классы). З.Ы. Слово override - это фишка шарпа, которой не было в С++, здорово облегчающая чтение кода. Всегда видно, где объявление метода, а где - перекрытая реализация. -------------------- ![]() |
|||
|
||||
| Elfet |
|
|||
![]() Белый и Пушистый ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 3776 Регистрация: 2.4.2003 Репутация: нет Всего: 16 |
Ещё больше запутался. Объясните ещё раз, чем отличаеться обысное переопределение, от переопределения виртуального метода?
Так же как и в C++? Про указатели в C++ я знаю, что можно присваивать указатели друг к другу только одного типа. За исключением нетепезированного указателя, ему можно присвоить любой указатель. С указателями на классы видимо что-то не допёр. Ссылке на предку можно присваивать ссылку на потомка и на оборот? Перекрытая реализация - это и есть полиморфизм? VMT? |
|||
|
||||
| mr.DUDA |
|
||||||||
|
3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
"Обычное переопределение" - такого термина нет. Есть три похожих термина: - перегруженный метод: два или более метода одного и того же класса, либо базового класса; с одинаковым именем, но разным набором аргументов; - перекрытый метод: два метода - базового и производного классов - с тем же именем, с тем же набором аргументов, и со спецификатором (в базовом классе - virtual; во всех производных - override); - скрывающий метод (м.б. немного неточное определение): два метода - базового и производного классов - то же что и overriden, но в производном классе есть спецификатор "new", а в базовом - либо virtual, либо override; даёт возможность в производном классе "забыть" о виртуальности метода - вообще очень и очень редко используемый спецификатор, я бы советовал на него забить и использовать только в случаях когда это действительно необходимо. В С++ можно присвоить одному указателю другой указатель. Там вообще нет проверки типов в рантайме, только на этапе компиляции; это легко обходится промежуточным приведением к void*
Да. То есть пройдёт такой код:
но не пройдёт код (на этапе компиляции, и более того - если обмануть через промежуточное присвоение object - выдаст exception в рантайме):
Вызов виртуального метода по его имени, зная только ссылку (указатель) на объект - это есть полиморфизм. Независимо от языка программирования. -------------------- ![]() |
||||||||
|
|||||||||
| Elfet |
|
||||||||
![]() Белый и Пушистый ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 3776 Регистрация: 2.4.2003 Репутация: нет Всего: 16 |
Ещё хочу спросить:
тут мы создаём объект Window и теряем сразуже теряем ссылку на него? Правильнее было бы сделать вот так?:
И ещё одно я понимаю полиморфизм вот так:
С new будет вот так-вот:
Я правильно понимаю? PS Конструкторы не наследуются? |
||||||||
|
|||||||||
| mr.DUDA |
|
|||
|
3D-маньяк ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 8244 Регистрация: 27.7.2003 Где: город-герой Минск Репутация: 110 Всего: 232 |
Ничего мы не теряем - ссылка помещается в первый элемент массива winArr. К слову, Window[] это - массив ссылок на объекты класса Window. Правильно. Только это не полиморфизм, а сокрытие метода. Если преобразовать ссылку c2 обратно в базовый класс - Print будет вызываться как метод класса MyClass. Другими словами, при использовании new полиморфизм "отменяется" только если вызывать метод через ссылку на тип, скрывший метод. Не наследуются. Нужно явно вызывать конструктор базового класса из конструктора класса-наследника. Это не относится к дефолтным конструкторам (конструктор без аргументов, который всегда есть у класса при условии, что нет ни одного явно опрелелённого конструктора). -------------------- ![]() |
|||
|
||||
| Elfet |
|
||||||||
![]() Белый и Пушистый ![]() ![]() ![]() ![]() Профиль Группа: Awaiting Authorisation Сообщений: 3776 Регистрация: 2.4.2003 Репутация: нет Всего: 16 |
А можно вот так?
? Я так понял вот в этой строчке мы не создаём никаких объектов класса Window, а только массив ссылок на класс Window.
А потом создаём объекты производного класса. И если бы не был виртуально переопределён метод DrawWindow, то он вызвался как метод Window::DrawWindow? В C++ подобная конструкция работала так же?
Это сообщение отредактировал(а) Elfet - 26.10.2006, 21:08 |
||||||||
|
|||||||||
![]()
|
| Прежде чем создать тему, посмотрите сюда: | |
|
|
Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов. Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :) Так же не забывайте отмечать свой вопрос решенным, если он таковым является :) Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |