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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Непонятные пример полиморфизма. Полиморфизм. 
V
    Опции темы
Elfet
  Дата 9.10.2006, 21:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Белый и Пушистый
****


Профиль
Группа: Awaiting Authorisation
Сообщений: 3776
Регистрация: 2.4.2003

Репутация: нет
Всего: 16



Меня интересует в C# полиморфизм тоже самое , что и в С++?

В книжке приводиться вот такой пример:
Код

using System;

public class Window
{

 public Window(int top, int left)
 {
   this.top = top;
   this.left = left
 }
 public virtual void DrawWindow()
  {
    Console.WriteLine("Window:{0}, {1}", top, left);
  }
  protected int top;
  protected int left;
}

public class ListBox: Window
{
   public ListBox(int top, int left, string con): base(top, left)
   {
      this.con=con;
   }
   public override void DrawWindow()
  {
    base.DrawWindow();
     Console.WriteLine("Text:{0}",con);
  }
  private string con;
}
public class Tester
{
    static void Main()
    {
      Window win = new Window(1,2);
      ListBox lb = new ListBox(3,4,"text1");
       win.DrawWindow();
       lb.DrawWindow();

     Window[] winArr = new Window[3];
     winArr[0] = new Window(1,2);
     winArr[1] = new ListBox(3,4,"text2");
     for(int i=0;i<3;i++)
      {
         winArr[i].DrawWindow();
       }
    } 
}


Я не понимаю вот этот код:
Код

     Window[] winArr = new Window[3];
     winArr[0] = new Window(1,2);
     winArr[1] = new ListBox(3,4,"text2");
     for(int i=0;i<3;i++)
      {
         winArr[i].DrawWindow();
       }


Зачем здесь использовать полиморфизм? Точно такой же эффект будет если просто переопределить метод класса?

Код

     Window[] winArr = new Window[3];
     winArr[0] = new Window(1,2);


Как такое возможно? Это не всё равно что если сделать вот это? :

Код

      Window win = new Window(1,2);
      win = new ListBox(3,4,"text1");







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


Python Dev.
****


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

Репутация: 9
Всего: 62



Цитата(Elfet @  9.10.2006,  22:44 Найти цитируемый пост)
Как такое возможно? Это не всё равно что если сделать вот это? :

win = new ListBox(3,4,"text1"); - тут объект ListBox приводится к cвоему предку Window, а значит в цикле for будет вызван метод класса Window.
Таким образом тут показано что любой дочерний тип можно привести к родительскому типу.
Вот например:
Код

MyClass M1 = new MyClass();
Object O = M1;
MyClass M2 = (MyClass)O;

PM WWW   Вверх
Elfet
Дата 9.10.2006, 22:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Белый и Пушистый
****


Профиль
Группа: Awaiting Authorisation
Сообщений: 3776
Регистрация: 2.4.2003

Репутация: нет
Всего: 16



Цитата
win = new ListBox(3,4,"text1"); - тут объект ListBox приводится к cвоему предку Window

Что-то не понял. Тут происходит неявное преобразование типов? 
Так если win являеться после win = new ListBox(3,4,"text1"); объектом класса Window, то с какой стати вызывать public override void DrawWindow()

Цитата(Ch0bits @  9.10.2006,  23:11 Найти цитируемый пост)
MyClass M1 = new MyClass();
Object O = M1;
MyClass M2 = (MyClass)O;

Object O = M1  что происходит при таком действии? Если же не перегруженна операция преобразования типа?


Это сообщение отредактировал(а) Elfet - 9.10.2006, 22:25


--------------------
PM MAIL WWW Skype   Вверх
Ch0bits
Дата 9.10.2006, 22:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Python Dev.
****


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

Репутация: 9
Всего: 62



Цитата(Elfet @  9.10.2006,  23:22 Найти цитируемый пост)
с какой стати вызывать public override void DrawWindow()

Этот метод не вызывается, т.к. является часть класс ListBox, который при создании сразу же приводится в предку Window.

Добавлено @ 22:37 
Цитата(Elfet @  9.10.2006,  23:22 Найти цитируемый пост)
Object O = M1  что происходит при таком действии? Если же не перегруженна операция преобразования типа?

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

Это сообщение отредактировал(а) Ch0bits - 9.10.2006, 22:34
PM WWW   Вверх
Elfet
Дата 9.10.2006, 22:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Белый и Пушистый
****


Профиль
Группа: Awaiting Authorisation
Сообщений: 3776
Регистрация: 2.4.2003

Репутация: нет
Всего: 16



А каким способом он приводиться?
В книжке этим примером объяснялся полиморфизм и говорилось, что поскольку он объявлен ключевым словом virtual и производные классы переопределили его, то будет вызван DrawWindow() класса ListBox


--------------------
PM MAIL WWW Skype   Вверх
Ch0bits
Дата 9.10.2006, 22:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Python Dev.
****


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

Репутация: 9
Всего: 62



Если в описании метода есть Virtual, то он считается виртуальным, т.е. ты можешь перекрыть его в классах наследниках.

Добавлено @ 22:53 
Попробуй скомпилировать без Virtual, тогда получишь ошибку, потому что не виртуальные методы нельзя переопределять, их можно только заного объявлять через new. 
PM WWW   Вверх
Elfet
Дата 9.10.2006, 22:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Белый и Пушистый
****


Профиль
Группа: Awaiting Authorisation
Сообщений: 3776
Регистрация: 2.4.2003

Репутация: нет
Всего: 16



Не понял. перекрыть в классах наследниках - это как?

Если метод класса переопределён как виртуальная ф-ия, то в производном классе заменяеться не только метод, но и все вызовы его в дргих методах класса.
Тут происходит позднее связывание через VMT?

Добавлено @ 23:01 
Цитата(Ch0bits @  9.10.2006,  23:49 Найти цитируемый пост)
Попробуй скомпилировать без Virtual, тогда получишь ошибку, потому что не виртуальные методы нельзя переопределять, их можно только заного объявлять через new.  

ТОгда зачем оно нужно вообще в этом примере? Если можно обойтись без virtual и override, а использовать new ?


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


Python Dev.
****


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

Репутация: 9
Всего: 62



Цитата(Elfet @  9.10.2006,  23:59 Найти цитируемый пост)
перекрыть в классах наследниках - это как?

Проще говоря, применять к методам класса родителя ключевое слово Override.  smile 

Цитата(Elfet @  9.10.2006,  23:59 Найти цитируемый пост)
Если можно обойтись без virtual и override, а использовать new ? 

Это плохой стиль.
PM WWW   Вверх
Ch0bits
Дата 10.10.2006, 06:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Python Dev.
****


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

Репутация: 9
Всего: 62



new используют, когда хотят изменить прототип метода, например:
Код

class A
{
    public int void V() {...}
}
class B : A
{
    new double void V(int A) {...}
}

PM WWW   Вверх
mr.DUDA
Дата 10.10.2006, 11:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 110
Всего: 232



Elfet, 
Цитата(Elfet @  9.10.2006,  22:22 Найти цитируемый пост)
Так если win являеться после win = new ListBox(3,4,"text1"); объектом класса Window, то с какой стати вызывать public override void DrawWindow()

win не является объектом класса Window, а всего лишь ссылкой на объект класса Window или любого производного класса от Window (каким и является ListBox).

Цитата(Elfet @  9.10.2006,  22:22 Найти цитируемый пост)
MyClass M1 = new MyClass();
Object O = M1;
MyClass M2 = (MyClass)O;

Object O = M1  что происходит при таком действии? Если же не перегруженна операция преобразования типа?

Если знаком с С++, то можешь понять аналогию: принцип тот же, что и с указателями. Только в шарпе вместо указателей - ссылки. Присвоение переменной типа A значения типа B - то же самое что присвоение указателю A* значения из указателя B* (только для ссылочных типов, какими и являются классы).

З.Ы. Слово override - это фишка шарпа, которой не было в С++, здорово облегчающая чтение кода. Всегда видно, где объявление метода, а где - перекрытая реализация.


--------------------
user posted image
PM MAIL WWW   Вверх
Elfet
Дата 10.10.2006, 21:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Белый и Пушистый
****


Профиль
Группа: Awaiting Authorisation
Сообщений: 3776
Регистрация: 2.4.2003

Репутация: нет
Всего: 16



Ещё больше запутался. Объясните ещё раз, чем отличаеться обысное переопределение, от переопределения виртуального метода?
Так же как и в C++?

Про указатели в C++ я знаю, что можно присваивать указатели друг к другу только одного типа. За исключением нетепезированного указателя, ему можно присвоить любой указатель.  smile 
С указателями на классы видимо что-то не допёр. Ссылке на предку можно присваивать ссылку на потомка и на оборот?

Перекрытая реализация - это и есть полиморфизм? VMT? 


--------------------
PM MAIL WWW Skype   Вверх
mr.DUDA
Дата 10.10.2006, 23:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 110
Всего: 232



Цитата(Elfet @  10.10.2006,  21:43 Найти цитируемый пост)
Ещё больше запутался. Объясните ещё раз, чем отличаеться обысное переопределение, от переопределения виртуального метода?Так же как и в C++?

"Обычное переопределение" - такого термина нет. Есть три похожих термина:
- перегруженный метод: два или более метода одного и того же класса, либо базового класса; с одинаковым именем, но разным набором аргументов;
- перекрытый метод: два метода - базового и производного классов - с тем же именем, с тем же набором аргументов, и со спецификатором (в базовом классе - virtual; во всех производных - override);
- скрывающий метод (м.б. немного неточное определение): два метода - базового и производного классов - то же что и overriden, но в производном классе есть спецификатор "new", а в базовом - либо virtual, либо override; даёт возможность в производном классе "забыть" о виртуальности метода - вообще очень и очень редко используемый спецификатор, я бы советовал на него забить и использовать только  в случаях когда это действительно необходимо.

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

В С++ можно присвоить одному указателю другой указатель.
Там вообще нет проверки типов в рантайме, только на этапе компиляции; это легко обходится промежуточным приведением к void*

Цитата(Elfet @  10.10.2006,  21:43 Найти цитируемый пост)
С указателями на классы видимо что-то не допёр. Ссылке на предку можно присваивать ссылку на потомка и на оборот?

Да. То есть пройдёт такой код:
Код
class A {}
class B : A {}

class Program
{
  static void Main()
  {
      A objA = new B();
  }
}


но не пройдёт код (на этапе компиляции, и более того - если обмануть через промежуточное присвоение object - выдаст exception в рантайме):
Код
class A {}
class B : A {}

class Program
{
  static void Main()
  {
      B objB = new A();
  }
}


Цитата(Elfet @  10.10.2006,  21:43 Найти цитируемый пост)
Перекрытая реализация - это и есть полиморфизм? VMT? 

Вызов виртуального метода по его имени, зная только ссылку (указатель) на объект - это есть полиморфизм. Независимо от языка программирования.


--------------------
user posted image
PM MAIL WWW   Вверх
Elfet
  Дата 26.10.2006, 15:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Белый и Пушистый
****


Профиль
Группа: Awaiting Authorisation
Сообщений: 3776
Регистрация: 2.4.2003

Репутация: нет
Всего: 16



 smile 
Ещё хочу спросить:
Код

     Window[] winArr = new Window[1];
     winArr[0] = new Window(1,2);

тут мы создаём объект Window и теряем сразуже теряем ссылку на него?
Правильнее было бы сделать вот так?:
Код

     Window winArr;
     winArr = new Window(1,2);



И ещё одно я понимаю полиморфизм вот так:
Код

using System;
public class MyClass
{
 public MyClass(string s)
 {
   this.str = s;
 }
 public virtual void Print()
  {
    Console.WriteLine("{0}", str);
  }
 public void PrintTwice()
  {
    Print(str);
    Print(str);
  }
  protected string str;
}
public class MySecondClass: MyClass
{
   public MySecondClass(string s): base(s)
   {
   }
   public override void Print()
  {
     Console.WriteLine("({0})",str);
  }
}
public class Tester
{
    static void Main()
    {
      MyClass c1 = new MyClass("C1");
      MySecondClass c2 = new MySecondClass("C2");
      c1.Print();   // напечатает С1
      c1.PrintTwice();  // напечатает С1С1
      c2.Print(); // напечатает (С2)
      c2.PrintTwice(); // напечатает (С2)(С2) !!!!!!
    } 
}


С new будет вот так-вот:
Код

using System;
public class MyClass
{
 public MyClass(string s)
 {
   this.str = s;
 }
 public void Print()
  {
    Console.WriteLine("{0}", str);
  }
 public void PrintTwice()
  {
    Print(str);
    Print(str);
  }
  protected string str;
}
public class MySecondClass: MyClass
{
   public MySecondClass(string s): base(s)
   {
   }
   public new void Print()
  {
     Console.WriteLine("({0})",str);
  }
}
public class Tester
{
    static void Main()
    {
      MyClass c1 = new MyClass("C1");
      MySecondClass c2 = new MySecondClass("C2");
      c1.Print();   // напечатает С1
      c1.PrintTwice();  // напечатает С1С1
      c2.Print(); // напечатает (С2)
      c2.PrintTwice(); // напечатает С2С2 !!!!!!
    } 
}


Я правильно понимаю?

PS Конструкторы не наследуются?


--------------------
PM MAIL WWW Skype   Вверх
mr.DUDA
Дата 26.10.2006, 19:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


3D-маньяк
****


Профиль
Группа: Экс. модератор
Сообщений: 8244
Регистрация: 27.7.2003
Где: город-герой Минск

Репутация: 110
Всего: 232



Цитата(Elfet @  26.10.2006,  15:25 Найти цитируемый пост)
тут мы создаём объект Window и теряем сразуже теряем ссылку на него?

Ничего мы не теряем - ссылка помещается в первый элемент массива winArr. К слову, Window[] это - массив ссылок на объекты класса Window.

Цитата(Elfet @  26.10.2006,  15:25 Найти цитируемый пост)
Я правильно понимаю?

Правильно. Только это не полиморфизм, а сокрытие метода. Если преобразовать ссылку c2 обратно в базовый класс - Print будет вызываться как метод класса MyClass. Другими словами, при использовании new полиморфизм "отменяется" только если вызывать метод через ссылку на тип, скрывший метод.

Цитата(Elfet @  26.10.2006,  15:25 Найти цитируемый пост)
PS Конструкторы не наследуются?

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


--------------------
user posted image
PM MAIL WWW   Вверх
Elfet
Дата 26.10.2006, 21:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Белый и Пушистый
****


Профиль
Группа: Awaiting Authorisation
Сообщений: 3776
Регистрация: 2.4.2003

Репутация: нет
Всего: 16



Цитата(mr.DUDA @  26.10.2006,  20:01 Найти цитируемый пост)

Ничего мы не теряем - ссылка помещается в первый элемент массива winArr. К слову, Window[] это - массив ссылок на объекты класса Window.

А можно вот так?
Код

     Window[1] *winArr;
     winArr[0] = new Window(1,2);

?
Я так понял вот в этой строчке мы не создаём никаких объектов класса Window, а только массив ссылок на класс Window.
Код

     Window[] winArr = new Window[1];

А потом создаём объекты производного класса. И если бы не был виртуально переопределён метод DrawWindow, то он вызвался как метод Window::DrawWindow?
В C++ подобная конструкция работала так же?
Код

Window * w[1];
w[0] = new ListBox(3,4,"text2");



Цитата(mr.DUDA @  26.10.2006,  20:01 Найти цитируемый пост)
Правильно. Только это не полиморфизм, а сокрытие метода. Если преобразовать ссылку c2 обратно в базовый класс - Print будет вызываться как метод класса MyClass. Другими словами, при использовании new полиморфизм "отменяется" только если вызывать метод через ссылку на тип, скрывший метод.



Это сообщение отредактировал(а) Elfet - 26.10.2006, 21:08


--------------------
PM MAIL WWW Skype   Вверх
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

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


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

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


 




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


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

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