![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Вопрос про ООП [D7, 2003]
ВаняЯ © (2007-12-06 21:42:00)У меня есть класс и его наследник. В коде программы в зависимости от условия нужно создавать или изначальный экземпляр класса или его наследник. Как в таком случае следует поступить? (Ну переменная должна быть одна, см. неработающий пример)
TMyClass1 = class(...)
private
Timer: TTimer;
....
FStr1: string;
public
constructor Create; virtual;
procedure Go1; virtual;
property str1: string read FStr1 write FStr1;
end;
TMyClass2 = class(TMyClass1)
private
FStr2: string;
....
public
constructor Create; override;
procedure Go1; override;
property str2: string read FStr2 write FStr2;
end;
------
var
Class: TMyClass1;
begin
Class := TMyCalss2.Create;
Class.str2 := 'test'; // Error
Sergey Masloff (2007-12-06 22:17:00) [1]Юрий Зотов © (06.12.07 22:01) [5]
Дело-то обычное только использовать нужно с осторожностью а то ведь появится класс TMyClass3 у которого нет str2 а приведение к нему сработает
program Project2;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TMyClass = class(TObject)
constructor Create(); virtual;
end;
TMyClass2 = class(TMyClass)
fInt : Integer;
fInt2 : Integer;
constructor Create(); reintroduce; override;
end;
TMyClass3 = class(TMyClass)
fInt : Integer;
constructor Create(); reintroduce; override;
end;
var
c : TMyClass;
{ TMyClass }
constructor TMyClass.Create;
begin
end;
{ TMyClass2 }
constructor TMyClass2.Create;
begin
inherited;
fInt := 1;
fInt2 := 2;
end;
{ TMyClass3 }
constructor TMyClass3.Create;
begin
inherited;
fInt := 3;
end;
begin
c := TmyClass3.Create();
Writeln(TMyClass2(c).fint);
Writeln(TMyClass2(c).fint2);
Readln;
end.
Причем в этом примере ладно а в реальном приложении он почитает что-то за границами своего экземпляра.
Ты-то это знаешь, а вот знает ли это каждый?
Юрий Зотов (2007-12-06 22:01:00) [2]> Sergey Masloff (06.12.07 21:56) [4]
Аналог - TStrings и TStringList. Потомок расширяет интерфейс предка.
Обычное дело - объявляем переменную класса предка, а создаем экземпляр потомка. Если юзаем НЕрасширенный интерфейс, то делаем это напрямую (а полиморфизм сохраняется), если расширенный - приводим класс.
Юрий Зотов (2007-12-06 21:56:00) [3]> ВаняЯ (06.12.07 21:53) [2]
Нормальная. В VCL подобное часто используется.
Sergey Masloff (2007-12-06 21:56:00) [4]Юрий Зотов © (06.12.07 21:50) [1]
А тогда на фига весь сыр-бор? Если хочется полиморфизма то интерфес объекта должен быть одинаков в данном контексте. То есть уж либо
TMyClass1 = class(...)
private
Timer: TTimer;
....
FStr1: string;
public
constructor Create; virtual;
procedure Go1; virtual;
property str1: string read FStr1 write FStr1;
property str2: string read DoNothing write DoNothing;
end;
либо другие альтернативные механизмы.
Вопрос естественно не тебе а автору топика ;-)
ВаняЯ (2007-12-06 21:53:00) [5]А такая практика, как у меня в примере - нормальная, или это извращение?
Юрий Зотов (2007-12-06 21:50:00) [6]Нужно подсказать компилятору фактический класс переменной. Иначе он использует тот, с которым она объявлена, а в нем str2 нет.
var
AClass: TMyClass1;
begin
AClass := TMyClass2.Create;
TMyClass2(AClass).str2 := 'test';