Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2008.07.27;
Скачать: [xml.tar.bz2];

Вниз

Корректность конструкции при переопределении конструктора   Найти похожие ветки 

 
Тын-Дын ©   (2008-06-24 15:14) [0]

Насколько корректна подобная конструкция при определении классов?

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type

 TForm1 = class(TForm)
   Button1: TButton;
 private
   { Private declarations }
 public
   { Public declarations }
 end;

 TTestThread=class(TThread)
 private
   FParam: String;
   constructor CreateThr(const Param: String);
 protected
   procedure Execute; override;
 public
   class function Create(const Param: String): TTestThread;
   procedure Terminate;
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

{ TTestThread }

class function TTestThread.Create(const Param: String): TTestThread;
begin
 try
   Result := TTestThread.CreateThr(Param);
 except
   Result := nil;
 end;
end;

constructor TTestThread.CreateThr(const Param: String);
begin
 inherited Create(True);
 FParam := Param;
 FreeOnTerminate := True;
 Resume;
end;

procedure TTestThread.Execute;
begin
//
end;

procedure TTestThread.Terminate;
begin
 TThread(Self).Terminate;
end;

end.


 
Тын-Дын ©   (2008-06-24 15:14) [1]

Сорри, не тот тег выставил.

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type

 TForm1 = class(TForm)
   Button1: TButton;
 private
   { Private declarations }
 public
   { Public declarations }
 end;

 TTestThread=class(TThread)
 private
   FParam: String;
   constructor CreateThr(const Param: String);
 protected
   procedure Execute; override;
 public
   class function Create(const Param: String): TTestThread;
   procedure Terminate;
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

{ TTestThread }

class function TTestThread.Create(const Param: String): TTestThread;
begin
 try
   Result := TTestThread.CreateThr(Param);
 except
   Result := nil;
 end;
end;

constructor TTestThread.CreateThr(const Param: String);
begin
 inherited Create(True);
 FParam := Param;
 FreeOnTerminate := True;
 Resume;
end;

procedure TTestThread.Execute;
begin
//
end;

procedure TTestThread.Terminate;
begin
 TThread(Self).Terminate;
end;

end.


 
Игорь Шевченко ©   (2008-06-24 15:29) [2]


> procedure TTestThread.Terminate;
> begin
>  TThread(Self).Terminate;
> end;


непонятно приведение типа, вместо указания inherited Terminate;


> class function TTestThread.Create(const Param: String):
> TTestThread;
> begin
>  try
>    Result := TTestThread.CreateThr(Param);
>  except
>    Result := nil;
>  end;
> end;


непонятно, куда девается информация об исключении.

непонятно, куда будет указывать результат, если поток успеет завершиться до возврата управления из конструктора и сработает FreeOnTerminate

То есть, я бы вообще не рекомендовал использовать указатель на объект TThread, если у него задано свойство FreeOnTerminate


 
Тын-Дын ©   (2008-06-24 15:34) [3]


> Игорь Шевченко ©   (24.06.08 15:29) [2]


Terminate, на самом деле, у меня по другому определено.
Это просто пример.
В реальном проекте такой вид:

procedure TThrSockClient.Terminate;
begin
 FTerminated := True;
 PostThreadMessage(ThreadId,WM_QUIT,0,0);
end;


 
Тын-Дын ©   (2008-06-24 15:35) [4]

Да, и про исключение забыл. Спасибо.

class function TTestThread.Create(const Param: String): TTestThread;
begin
try
  Result := TTestThread.CreateThr(Param);
except
  Result := nil;
  Raise;
end;
end;


 
Тын-Дын ©   (2008-06-24 15:37) [5]

Но исключение тут только по необходимости.

Возможно такое использование:

var
 t: TTestThread;
begin
 t := TTestThread.Create("Test");
 if not Assigned(t) then ...


 
Игорь Шевченко ©   (2008-06-24 15:41) [6]

Тын-Дын ©   (24.06.08 15:37) [5]

непонятно, куда будет указывать результат, если поток успеет
завершиться до возврата управления из конструктора и сработает
FreeOnTerminate


> Но исключение тут только по необходимости.


А о причине исключения узнать ?


 
Тын-Дын ©   (2008-06-24 16:05) [7]


> Игорь Шевченко c   (24.06.08 15:41) [6]
> Тын-Дын c   (24.06.08 15:37) [5]
>
> непонятно, куда будет указывать результат, если поток успеет
>
> завершиться до возврата управления из конструктора и сработает
>
> FreeOnTerminate


Ну такая конструкция создаётся для конкретной задачи, поэтому поток не сможет завершиться до выхода из конструктора. но хотелось бы узнать, конечно, подводные камни при таком подходе.

Тогда возможно Resume нужно выполнять в процедуре Create:

class function TTestThread.Create(const Param: String): TTestThread;
begin
  try
    Result := TTestThread.CreateThr(Param);
    Result.Resume;
  except
    Result := nil;
    Raise;
  end;
end;



> А о причине исключения узнать ?


Это да, если необходимо... Тут можно предусмотреть...


 
Игорь Шевченко ©   (2008-06-24 16:16) [8]


> Тогда возможно Resume нужно выполнять в процедуре Create:


наверное. Но в любом случае я не вижу целесообразности возвращать указатель на объект, который может быть удален без ведома в произвольный момент времени.


>  except
>     Result := nil;
>     Raise;
>   end;


и какой смысл имеет в этом случае result ?


 
Игорь Шевченко ©   (2008-06-24 16:23) [9]

Я для создания автоматически уничтожаемых потоков использую простой вызов TAutoFreeThread.Create (params);
когда мне надо узнать о состоянии потока, заводится переменная AutoFreeThreadRunning, соответственно, изменяемая в методе Execute потока. Каковую переменную, без всяких критических секций я опрашиваю, например, по таймеру.

Но у меня потоки такого рода выполняют некие SQL-запросы и заполняют некие DataSet"ы, поэтому результат все равно будет виден глазами, проблем с синхронизацией нету.


 
Тын-Дын ©   (2008-06-24 16:27) [10]


> Но в любом случае я не вижу целесообразности возвращать
> указатель на объект, который может быть удален без ведома
> в произвольный момент времени.


В принципе да.
Поток после создания ждёт от других потоков получения некоторых команд (передача/прием данных). В принципе, неуправляемо поток не должен разрушаться, а код хотелось упростить все-таки - потоки будут достаточно часто разрушаться (программированием пула потоков не хочется заморачиваться).

Видимо, сделаю FreeOnTerminate := False;, тем более, что всё равно придется список объектов хранить где-то.


 
Тын-Дын ©   (2008-06-24 16:31) [11]


> и какой смысл имеет в этом случае result ?


Уже убрал-)


 
Юрий Зотов ©   (2008-06-24 17:20) [12]

> Тын-Дын ©   (24.06.08 16:31) [11]

> Уже убрал-)

После чего смысл функции Create тоже исчезает.

Почему просто не переопределить конструктор, без всяких извращений?


 
Тын-Дын ©   (2008-06-24 17:49) [13]


> Юрий Зотов ©   (24.06.08 17:20) [12]
> > Тын-Дын ©   (24.06.08 16:31) [11]
>
> > Уже убрал-)
>
> После чего смысл функции Create тоже исчезает.
>
> Почему просто не переопределить конструктор, без всяких
> извращений?


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

Изначальная задача:
Есть сервер W2003, на нём RAdmin, Squid-proxy(порт 2222).

На сервере открыто для доступа 2 порта - RDP и 4899(Radmin).

Задача такая:
Radmin пересадить на другой порт(4900), сделать TCP-Mapping с 4899 на 2222.
При этом при подключении клиентом RAdmn на порт 4899 программа должна распознавать сигнатуру RAdmin и маппирование должно производиться на порт 4900.

Реализовать решил в виде сервиса (сейчас простое маппирование сделано на компонентах Indy).
-----------

хм...

Пока писал, мысль пришла, что можно обойтись без дополнительной функции.

Вот как реализовано сейчас:

class function TThrSockClient.Create(const Addr: String;
 Port: Integer): TThrSockClient;
begin
 Result := TThrSockClient.CreateClient(Addr,port);
 Result.Resume;
 try
   Result.WaitStart;
 except
   Result.Terminate;
   Raise;
 end;
end;

constructor TThrSockClient.CreateClient(const Addr: String; Port: Integer);
begin
 inherited Create(True);
 FTag := CreateEvent(nil,True,False,nil);
 FPort := 0;
 FAddr := Addr;
 FPort := Port;
 FreeOnTerminate := True;
end;

procedure TThrSockClient.Execute;
var
 M: TMsg;
begin
 PeekMessage(M,0,0,0,PM_NoRemove);
 FSock := TClientSocket.Create(nil);
 FSock.OnConnecting := FSockConnecting;
 FSock.OnConnect := FSockConnect;
 FSock.OnDisconnect := FSockDisconnect;
 FSock.OnRead := FSockRead;
 FSock.OnWrite := FSockWrite;
 FSock.OnError := FSockError;
 FSock.Address := FAddr;
 FSock.Port := FPort;
 SetEvent(FTag);
 while (not Terminated) and (GetMessage(M,0,0,0)) do
 begin
   TranslateMessage(M);
   DispatchMessage(M);
 end;
end;

procedure TThrSockClient.Terminate;
begin
 FTerminated := True;
 PostThreadMessage(ThreadId,WM_QUIT,0,0);
end;

procedure TThrSockClient.WaitStart;
begin
 try
   if WaitForSingleObject(FTag,100)<>WAIT_OBJECT_0 then raise Exception.Create("Error create object");
 finally
   CloseHandle(FTag);
   FTag := 0;
 end;
end;


А ведь достаточно в конструкторе сделать так:

constructor TThrSockClient.CreateClient(const Addr: String; Port: Integer);
begin
 inherited Create(True);
 FTag := CreateEvent(nil,True,False,nil);
 FPort := 0;
 FAddr := Addr;
 FPort := Port;
 FreeOnTerminate := True;
 Resume;
 WaitStart;
end;


 
Юрий Зотов ©   (2008-06-24 17:55) [14]

> Тын-Дын ©   (24.06.08 17:49) [13]

О чем и речь - просто переопределить конструктор.


 
Тын-Дын ©   (2008-06-24 23:51) [15]

Спасибо всем.

Кстати, вопрос немного всё-таки другой: не нарушаю ли я какие-либо принципы ООП и есть ли подводные камни при таком замещении предопределённых методов?


 
Игорь Шевченко ©   (2008-06-25 00:02) [16]


> Кстати, вопрос немного всё-таки другой: не нарушаю ли я
> какие-либо принципы ООП


принципов всего три - наследование, инкапсуляция и полиморфизм.


> и есть ли подводные камни при таком замещении предопределённых
> методов?


да вроде нету. Компилятор автоматически знает, чьи статические методы вызывать



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2008.07.27;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.51 MB
Время: 0.008 c
6-1187976122
OrdJONY
2007-08-24 21:22
2008.07.27
Свой протокол


11-1186297255
MTsv DN
2007-08-05 11:00
2008.07.27
MultiSelect in TreeView


2-1214387731
Aggressor
2008-06-25 13:55
2008.07.27
WinXP rus, WinXP eng и кириллица


15-1212840446
Vlad Oshin
2008-06-07 16:07
2008.07.27
как работает и почему такой ответ


15-1213202010
Dmitry S
2008-06-11 20:33
2008.07.27
Упорядочивание mp3 архива.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский