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

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

Вопрос про ООП [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';


Наверх

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