![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Вопрос по наследованию
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 устанавливает первое, а унаследованный - второе.