Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Создание объекта от TClass


Автор: Budy 20.11.2009, 08:27
:Привествую

Есть код
Код
uses
  Dialogs;

type
  TBaseCls = class
    constructor Create;    
  end;
  
var
  b : TBaseCls;  
  p : ^TObject;
  c : TClass;

constructor TBaseCls.Create;    
begin
  ShowMessage(Self.ClassType.ClassName);
end;

begin
  c := TBaseCls;
  
  // Block A
  GetMem(p, SizeOf(TObject));
  p^ := c.Create;
  p^.Free;
  FreeMem(p);
  
  // Block B
  b := TBaseCls.Create;
  b.Free;
end.


При выполнении блока A создается объект класса TObject, при том TBaseCls.Create не выполняется, хотя указан этот класс.
Помогите плиз выбрать нужный подход.

Для блока A необходимо указать класс, от которого будет создан объект.
Я написал обрезанный пример. Строю иерархическое дерево классов, а потому в блоке A не будет известен класс TBaseCls.

Автор: cemick 20.11.2009, 10:07
 smile 

Чт я не понял, а зачем столь хитрый код, использование указателя на класс.. опишите более подробно задачу, что то мне подсказывает, что можно намного проще.

Автор: Budy 20.11.2009, 11:13
Хочу написать класс листинга с автоматическим созданием и удалением элементов.

Код

type
TPointers : Array of Pointer;

TBaseList = class
  List : TPointers;
  ItemClass : TClass;
  constructor Create(AItemClass : TClass);
  procedure Add : TPointer;
  procedure Delete(Index : Integer);
  ...
end;

constuctor TBaseList.Create;
begin
  ItemClass := AItemClass;
end;

function TBaseList.Add;
begin
  GetMem(Result, SizeOf(TObject));
  Result^ := ItemClass.Create;
  SetLength(List, High(List)+2);
  List[High(List)] := Result;
end;


Код

var MyList : TBaseList;


Проблема в следующем. Есть класс
Код

type

TMyClass = class
  constructor Create; // стандартный метод для всех объектов, но я меняю на свой
end;

constructor TMyClass.Create;
begin
  // чего-нибудь
end;


Когда создаю MyList, я должен указать класс, от которого должны создаваться элементы списка.
MyList := TBaseList.Create(TMyClass);

Потом я создаю список, например вот так:
var o : Pointer;
o := MyList.Add;
TMyObject(o^).SampleProc;

Дак вот это самое "чего-нибудь" не происходит.

Автор: cemick 20.11.2009, 11:35
Передавать надо ссылку на класс

type TMyClassRef = class of TMyClass;

Автор: Budy 20.11.2009, 11:43
Цитата(cemick @  20.11.2009,  14:35 Найти цитируемый пост)
Передавать надо ссылку на классtype TMyClassRef = class of TMyClass;

хм...

Автор: Budy 20.11.2009, 12:13
Путем усиленных колебаний мозга во всех 8ми направлениях, пришел к такому виду (см.первый код):
Код
uses
  Dialogs;

type
  PMyObject = ^TMyObject;
  TMyObject = class
    procedure Init; dynamic; abstract;
  end;

  TMyClass = class of TMyObject;

  TMyObject1 = class(TMyObject)
    // Метод инициализации
    procedure Init; override;
  end;

  TMyObject2 = class(TMyObject)
    // Нет метода инициализцаии
  end;

procedure TMyObject1.Init;    
begin
  ShowMessage('Init');
end;

var
  p : PMyObject;
  c : TMyClass;

begin
  // Block A
  c := TMyObject1;
  GetMem(p, SizeOf(TObject));
  p^ := c.Create;
  try
    p^.Init;
  except; end;
  p^.Free;
  FreeMem(p);

  // Block B
  c := TMyObject2;
  GetMem(p, SizeOf(TObject));
  p^ := c.Create;
  try
    p^.Init;
  except; end;
  p^.Free;
  FreeMem(p);
end.


Блок try..except..end; будет выдавать ошибку в случае если метод Init в объекте не описан. Как можно проверить существование метода в классе?

Автор: Budy 20.11.2009, 12:34
Разобрался самостоятельно. Всем спасибо за внимание. Если кому интересно, пришел к следующему:
Код

uses
  Dialogs;

type
  PMyObject = ^TMyObject;
  TMyObject = class
  published
    procedure Init; virtual;
  end;

  TMyClass = class of TMyObject;

  TMyObject1 = class(TMyObject)
  published
    // Метод инициализации
    procedure Init; override;
  end;

  TMyObject2 = class(TMyObject)
    // Нет метода инициализцаии
  end;

procedure TMyObject.Init;
begin
end;

procedure TMyObject1.Init;    
begin
  ShowMessage('Init');
end;

var
  p : PMyObject;
  c : TMyClass;
  m : procedure;

begin
  // Block A
  c := TMyObject1;
  GetMem(p, SizeOf(TObject));
  p^ := c.Create;
  p^.Init;
  p^.Free;
  FreeMem(p);

  // Block B
  c := TMyObject2;
  GetMem(p, SizeOf(TObject));
  p^ := c.Create;
  p^.Init;
  p^.Free;
  FreeMem(p);
end.

Автор: cemick 20.11.2009, 12:51
oh my god... 

Я бы ваш код переделал так

Код

unit Unit2;

interface
uses
  Dialogs,  SysUtils;
type

  TMyObject = class
    procedure Init; dynamic; abstract;
  end;

  TMyClass = class of TMyObject;

  TMyObject1 = class(TMyObject)
    // Метод инициализации
    procedure Init; override;
  end;

  TMyObject2 = class(TMyObject)
    // Нет метода инициализцаии
  end;

implementation

procedure TMyObject1.Init;    
begin
  ShowMessage('Init');
end;

var
  p : TMyObject;
  c : TMyClass;

begin
  // Block A
  c := TMyObject1;

  p := c.Create;
  try
    p.Init;
  finally
    FreeAndNil(p);
  end;

  // Block B
  c := TMyObject2;
  p := c.Create;
  try
    try
     p.Init;
    except
      on E: EAbstractError do
      begin
        E := nil;
      end;
    end;
  finally
    FreeAndNil(p);
  end;
end.

Автор: Budy 20.11.2009, 13:36
cemick, это тоже хороший способ, подобный мне уже предлагали. Но я выяснил, что при дебаге он не удобен. У меня около ста объектов создается таким образом при старте программы smile
В любом случае спасибо.

Автор: cemick 20.11.2009, 14:37
Цитата(Budy @  20.11.2009,  13:36 Найти цитируемый пост)
cemick, это тоже хороший способ, подобный мне уже предлагали. Но я выяснил, что при дебаге он не удобен. У меня около ста объектов создается таким образом при старте программы 
В любом случае спасибо.

Я не к тому, что надо использовать try except EAbstractError(1. Можно добавить в список исключений которые не будут отлавливаться дебагером 2. Кто же знал что вам не важно,  абстарктный метод или нет), а я к тому, что зачем вам работа с указателями, нафига GetMem и прочие, так писать просто не красиво.

Автор: Budy 23.11.2009, 06:14
Цитата(cemick)
1. Можно добавить в список исключений которые не будут отлавливаться дебагером

Хм... было бы полезно узнать как это сделать.

Цитата(cemick)
а я к тому, что зачем вам работа с указателями, нафига GetMem и прочие, так писать просто не красиво.

Привычка работать с памятью привязалась ко мне еще с Pascal'я. Более надеждного и удобного способа управления объектами для себя лично не вижу.

Автор: cemick 23.11.2009, 09:45
Цитата(Budy @  23.11.2009,  06:14 Найти цитируемый пост)
Хм... было бы полезно узнать как это сделать.

Tools->Debuging Options -> Language Exceptions (Это в семерке)

Цитата(Budy @  23.11.2009,  06:14 Найти цитируемый пост)
Привычка работать с памятью привязалась ко мне еще с Pascal'я. Более надеждного и удобного способа управления объектами для себя лично не вижу. 

Это не есть плюс, теряется наглядность и прозрачность кода, повышается вероятность ошибки

Автор: CodeMonkey 23.11.2009, 16:12
Вообще-то для этих целей есть такая вещь, как виртуальный конструктор и class of.

Автор: Budy 24.11.2009, 05:56
Цитата(CodeMonkey @  23.11.2009,  19:12 Найти цитируемый пост)
Вообще-то для этих целей есть такая вещь, как виртуальный конструктор и class of.

Может у вас есть интересные примеры. Прошу выкладывайте  smile 

Автор: CodeMonkey 24.11.2009, 12:04
Да пример-то будет почти так же, как у вас. Только уберите Init, засуньте его код в конструктор и объявите Create виртуальным.
Код
type
  TMyObject = class
    constructor Create; virtual;
  end;

  TMyClass = class of TMyObject;

  TMyObject1 = class(TMyObject)
    constructor Create; override;
  end;

  TMyObject2 = class(TMyObject)
    // Нет метода инициализцаии
  end;

implementation

constructor TMyObject.Create;
begin
  inherited Create;
end;

constructor TMyObject1.Create;    
begin
  inherited Create;
  ShowMessage('Init');
end;

var
  p : TMyObject;
  c : TMyClass;
begin
  // Block A
  c := TMyObject1;
  p := c.Create;
  FreeAndNil(p);

  // Block B
  c := TMyObject2;
  p := c.Create;
  FreeAndNil(p);
end.


Автор: Budy 24.11.2009, 14:25
CodeMonkey, Init был переписан в связи с условием проверки на post Create. Вобщем, я отделил метод конструктора и метод инициализации объекта.

Автор: CodeMonkey 24.11.2009, 15:30
Цитата(Budy @  24.11.2009,  14:25 Найти цитируемый пост)
Вобщем, я отделил метод конструктора и метод инициализации объекта

Ну и зачем вы это сделали?

Мой пример - это один-к-одному ваш код из оригинального вопроса, только с исправленным багом (нет virtual у конструктора) и убранными ненужными указателями (http://transl-gunsmoker.blogspot.com/2009/09/blog-post.html).

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)