Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Вопрос по наследованию


753 ©   (2005-07-14 12:39:00) 

Есть описание (пример взят из книги):
type
 T1stObj = class
   i: Extended;
   procedure SetData(AValue: Extended)
 end;

 T2nd0bj = class(T1stObj)
   i: Integer;
   procedure SetData(AValue: Integer)
 end;

procedure T1stObj.SetData;
begin
 i := 1.0
end;

procedure T2nd0bj.SetData;
begin
 i := 1;
 inherited SetData(0.99) //?
end;
Вопрос такой: разве "inherited SetData(0.99)" не вызовет ошибки? Ведь в T2ndObj перекрыто поле i и оно имеет другой тип данных (Integer вместо Extended), поэтому и метод SetData T1stObj нельзя вызывать в потомке. Или я ошибаюсь? Или нет?


evvcom   (2005-07-14 14:13:00) [1]


> ... // Здесь глобальная переменная MyVar недоступна, потому
>  ... // что ее закрыла одноименная локальная переменная

Через имя модуля будет доступна. (Это не камень в огород Юрия, а уточнение для вопрошающих) :)


begin...end   (2005-07-14 14:08:00) [2]

> inherited   (14.07.05 14:06) [15]

Конструктор здесь нужно вызвать так: obj := T2nd0bj.Create.


Alexander Panov   (2005-07-14 14:07:00) [3]

inherited   (14.07.05 14:06) [15]
да я не про значение i, я про EAccessViolation...


Тогда в книжный магазин и изучать основы ООП.


inherited   (2005-07-14 14:06:00) [4]

да я не про значение i, я про EAccessViolation...


Alexander Panov   (2005-07-14 14:03:00) [5]

inherited   (14.07.05 13:59) [12]
ну попробуйте поставьте create - ничего не меняется (((


А вот покажи, какне меняется.


begin...end   (2005-07-14 14:02:00) [6]

> inherited   (14.07.05 13:59) [12]

А что должно быть? Оба поля будут равны единице. Всё правильно.


inherited   (2005-07-14 13:59:00) [7]

Skyle ©   (14.07.05 13:48) [11]

ну попробуйте поставьте create - ничего не меняется (((


Skyle   (2005-07-14 13:48:00) [8]


> begin
> obj.SetData(0);
> end;


А может obj ещё инициализировать надо? Объект там создать, конструктор вызвать....


Юрий Зотов   (2005-07-14 13:46:00) [9]

> 753   (14.07.05 13:32) [7]
Точно так.

> begin...end ©   (14.07.05 13:33) [8]
Точно так.  

> 753   (14.07.05 13:32) [7]
Обратите внимание на [8]. Здесь доступ к полю предка осуществляется другим способом - не через inherited, а прямым приведением класса (для полей inherited не прокатывает). То есть, прямым указанием компилятору, какое именно поле он должен в данном месте использовать при генерации машинного кода.

В случае inherited SetDataмы тоже напрямую указали компилятору, что в данном месте он должен сгенерить вызов метода предка, а не потомка. Для методов inherited работает.


inherited   (2005-07-14 13:41:00) [10]

может объяснит кто, почему это не работает?


unit Unit1;
interface
uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs;
type
 TForm1 = class(TForm)
   procedure FormCreate(Sender: TObject);
  end;
    T1stObj = class
    i: extended;
    public
    procedure SetData(AValue: Extended);
     end;
      T2nd0bj = class(T1stObj)
  i: Integer;
  public
  procedure SetData(AValue: Integer);
end;
var
 Form1: TForm1;
 obj: T2nd0bj;
implementation
{$R *.dfm}
procedure T1stObj.SetData;
begin
i := 1.0;
end;
procedure T2nd0bj.SetData;
begin
 i := 1;
inherited SetData(0.99); //?
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
obj.SetData(0);
end;
end.


begin...end   (2005-07-14 13:33:00) [11]

> Юрий Зотов ©   (14.07.05 13:20) [6]

> В ряде случаев обратиться к закрытому элементу предка
> все же можно - через директиву inherited.

Поскольку в данном случае речь идёт о полях, то, насколько я понимаю, inherited тут не пройдёт.

> 753   (14.07.05 12:39)

type
 TAncestor = class
   I: Integer;
 end;

 TDescendant = class(TAncestor)
   I: Integer;
 end;

var
 D: TDescendant;
begin
 D := TDescendant.Create;
 // Запись в поле TAncestor.I
 TAncestor(D).I := 1;
 // Запись в поле TDescendant.I
 D.I := 2;
 ShowMessageFmt('%d %d', [TAncestor(D).I, D.I])
end.


753   (2005-07-14 13:32:00) [12]

Большое спасибо всем, особенно Юрию Зотову.
Подводя итог, строчка "inherited SetData(0.99)" обращается к закрытому (недоступному напрямую) методу предка, который устанаавливает значение поля i: Extended в предке.


Юрий Зотов   (2005-07-14 13:20:00) [13]

> 753   (14.07.05 13:01) [4]

> Перекрытое (одноименное) поле предка недоступно в потомке;

Одноименное поле предка в потомке действительно напрямую недоступно, но не по причине его перекрытия. Тут налицо некая путаница в трактовке терминологии ООП.

Перекрываются (override) виртуальные (и динамические) методы. Статические же элементы класса (поля, свойства и статические методы) перекрыть невозможно. Даже если в потомке ввести такой же элемент с тем же именем, то он не пере кроет (в смысле ООП) а, согласно общим правилам видимости, просто за кроет одноименный элемент предка. Вот аналогичный пример без всякого ООП:

var
 MyVar: integer; // Глобальная переменная

procedure MyProc;
var
 MyVar: integer; // Локальная переменная
begin
 ... // Здесь глобальная переменная MyVar недоступна, потому
 ... // что ее закрыла одноименная локальная переменная
end;

В ряде случаев обратиться к закрытому элементу предка все же можно - через директиву inherited.


begin...end   (2005-07-14 13:07:00) [14]

> 753   (14.07.05 13:01) [4]
> Перекрытое (одноименное) поле предка недоступно в потомке

Доступно.


753   (2005-07-14 13:01:00) [15]

Дальше по тексту:
В этом примере разныеметоды с именем SetData присваивают значения разнымполям с именем i. Перекрытое (одноименное) поле предка недоступно в потомке; поэтому, конечно, два одноименных поля с именем i приведены только для примера.


Reindeer Moss Eater   (2005-07-14 12:57:00) [16]

наследуемый SetData принимает параметром Extended;
Ему и передают литерал 0.99.

Какие проблемы?


Fay   (2005-07-14 12:56:00) [17]

2 753   (14.07.05 12:39)
1) Проверить слабо?
2) Читал мельком, но выглядит вполне пристойно.


Юрий Зотов   (2005-07-14 12:55:00) [18]

> в T2ndObj перекрыто поле i

Поля не перекрываются, они добавляются. В классе T2ndObj два поля i - целое (введено в нем самом) и вещественное (унаследовано). Его "родной" метод SetData устанавливает первое, а унаследованный - второе.


Наверх

Титульная страница Поиск, карта сайта Написать письмо