Форум: "Основная";
Текущий архив: 2005.07.31;
Скачать: [xml.tar.bz2];
ВнизВопрос по наследованию Найти похожие ветки
← →
753 (2005-07-14 12:39) [0]Есть описание (пример взят из книги):
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 нельзя вызывать в потомке. Или я ошибаюсь? Или нет?
← →
Юрий Зотов © (2005-07-14 12:55) [1]> в T2ndObj перекрыто поле i
Поля не перекрываются, они добавляются. В классе T2ndObj два поля i - целое (введено в нем самом) и вещественное (унаследовано). Его "родной" метод SetData устанавливает первое, а унаследованный - второе.
← →
Fay © (2005-07-14 12:56) [2]2 753 (14.07.05 12:39)
1) Проверить слабо?
2) Читал мельком, но выглядит вполне пристойно.
← →
Reindeer Moss Eater © (2005-07-14 12:57) [3]наследуемый SetData принимает параметром Extended;
Ему и передают литерал 0.99.
Какие проблемы?
← →
753 (2005-07-14 13:01) [4]Дальше по тексту:
В этом примере разные методы с именем SetData присваивают значения разным полям с именем i. Перекрытое (одноименное) поле предка недоступно в потомке; поэтому, конечно, два одноименных поля с именем i приведены только для примера.
← →
begin...end © (2005-07-14 13:07) [5]> 753 (14.07.05 13:01) [4]
> Перекрытое (одноименное) поле предка недоступно в потомке
Доступно.
← →
Юрий Зотов © (2005-07-14 13:20) [6]> 753 (14.07.05 13:01) [4]
> Перекрытое (одноименное) поле предка недоступно в потомке;
Одноименное поле предка в потомке действительно напрямую недоступно, но не по причине его перекрытия. Тут налицо некая путаница в трактовке терминологии ООП.
Перекрываются (override) виртуальные (и динамические) методы. Статические же элементы класса (поля, свойства и статические методы) перекрыть невозможно. Даже если в потомке ввести такой же элемент с тем же именем, то он не перекроет (в смысле ООП) а, согласно общим правилам видимости, просто закроет одноименный элемент предка. Вот аналогичный пример без всякого ООП:
var
MyVar: integer; // Глобальная переменная
procedure MyProc;
var
MyVar: integer; // Локальная переменная
begin
... // Здесь глобальная переменная MyVar недоступна, потому
... // что ее закрыла одноименная локальная переменная
end;
В ряде случаев обратиться к закрытому элементу предка все же можно - через директиву inherited.
← →
753 (2005-07-14 13:32) [7]Большое спасибо всем, особенно Юрию Зотову.
Подводя итог, строчка "inherited SetData(0.99)" обращается к закрытому (недоступному напрямую) методу предка, который устанаавливает значение поля i: Extended в предке.
← →
begin...end © (2005-07-14 13:33) [8]> Юрий Зотов © (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.
← →
inherited (2005-07-14 13:41) [9]может объяснит кто, почему это не работает?
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.
← →
Юрий Зотов © (2005-07-14 13:46) [10]> 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 работает.
← →
Skyle © (2005-07-14 13:48) [11]
> begin
> obj.SetData(0);
> end;
А может obj ещё инициализировать надо? Объект там создать, конструктор вызвать....
← →
inherited (2005-07-14 13:59) [12]Skyle © (14.07.05 13:48) [11]
ну попробуйте поставьте create - ничего не меняется (((
← →
begin...end © (2005-07-14 14:02) [13]> inherited (14.07.05 13:59) [12]
А что должно быть? Оба поля будут равны единице. Всё правильно.
← →
Alexander Panov © (2005-07-14 14:03) [14]inherited (14.07.05 13:59) [12]
ну попробуйте поставьте create - ничего не меняется (((
А вот покажи, как не меняется.
← →
inherited (2005-07-14 14:06) [15]да я не про значение i, я про EAccessViolation...
← →
Alexander Panov © (2005-07-14 14:07) [16]inherited (14.07.05 14:06) [15]
да я не про значение i, я про EAccessViolation...
Тогда в книжный магазин и изучать основы ООП.
← →
begin...end © (2005-07-14 14:08) [17]> inherited (14.07.05 14:06) [15]
Конструктор здесь нужно вызвать так: obj := T2nd0bj.Create.
← →
evvcom © (2005-07-14 14:13) [18]
> ... // Здесь глобальная переменная MyVar недоступна, потому
> ... // что ее закрыла одноименная локальная переменная
Через имя модуля будет доступна. (Это не камень в огород Юрия, а уточнение для вопрошающих) :)
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2005.07.31;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.036 c