![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Корректность конструкции при переопределении конструктора
Тын-Дын © (2008-06-24 15:14:00)Насколько корректна подобная конструкция при определении классов?
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-25 00:02:00) [1]
> Кстати, вопрос немного всё-таки другой: не нарушаю ли я
> какие-либо принципы ООП
принципов всего три - наследование, инкапсуляция и полиморфизм.
> и есть ли подводные камни при таком замещении предопределённых
> методов?
да вроде нету. Компилятор автоматически знает, чьи статические методы вызывать
Тын-Дын (2008-06-24 23:51:00) [2]Спасибо всем.
Кстати, вопрос немного всё-таки другой: не нарушаю ли я какие-либо принципы ООП и есть ли подводные камни при таком замещении предопределённых методов?
Юрий Зотов (2008-06-24 17:55:00) [3]> Тын-Дын © (24.06.08 17:49) [13]
О чем и речь - просто переопределить конструктор.
Тын-Дын (2008-06-24 17:49:00) [4]
> Юрий Зотов © (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:20:00) [5]> Тын-Дын © (24.06.08 16:31) [11]
> Уже убрал-)
После чего смысл функции Create тоже исчезает.
Почему просто не переопределить конструктор, без всяких извращений?
Тын-Дын (2008-06-24 16:31:00) [6]
> и какой смысл имеет в этом случае result ?
Уже убрал-)
Тын-Дын (2008-06-24 16:27:00) [7]
> Но в любом случае я не вижу целесообразности возвращать
> указатель на объект, который может быть удален без ведома
> в произвольный момент времени.
В принципе да.
Поток после создания ждёт от других потоков получения некоторых команд (передача/прием данных). В принципе, неуправляемо поток не должен разрушаться, а код хотелось упростить все-таки - потоки будут достаточно часто разрушаться (программированием пула потоков не хочется заморачиваться).
Видимо, сделаюFreeOnTerminate := False;, тем более, что всё равно придется список объектов хранить где-то.
Игорь Шевченко (2008-06-24 16:23:00) [8]Я для создания автоматически уничтожаемых потоков использую простой вызов TAutoFreeThread.Create (params);
когда мне надо узнать о состоянии потока, заводится переменная AutoFreeThreadRunning, соответственно, изменяемая в методе Execute потока. Каковую переменную, без всяких критических секций я опрашиваю, например, по таймеру.
Но у меня потоки такого рода выполняют некие SQL-запросы и заполняют некие DataSet'ы, поэтому результат все равно будет виден глазами, проблем с синхронизацией нету.
Игорь Шевченко (2008-06-24 16:16:00) [9]
> Тогда возможно Resume нужно выполнять в процедуре Create:
наверное. Но в любом случае я не вижу целесообразности возвращать указатель на объект, который может быть удален без ведома в произвольный момент времени.
> except
> Result := nil;
> Raise;
> end;
и какой смысл имеет в этом случае result ?
Тын-Дын (2008-06-24 16:05:00) [10]
> Игорь Шевченко 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 15:41:00) [11]Тын-Дын © (24.06.08 15:37) [5]
непонятно, куда будет указывать результат, если поток успеет
завершиться до возврата управления из конструктора и сработает
FreeOnTerminate
> Но исключение тут только по необходимости.
А о причине исключения узнать ?
Тын-Дын (2008-06-24 15:37:00) [12]Но исключение тут только по необходимости.
Возможно такое использование:
var
t: TTestThread;
begin
t := TTestThread.Create('Test');
if not Assigned(t) then ...
Тын-Дын (2008-06-24 15:35:00) [13]Да, и про исключение забыл. Спасибо.
class function TTestThread.Create(const Param: String): TTestThread;
begin
try
Result := TTestThread.CreateThr(Param);
except
Result := nil;
Raise;
end;
end;
Тын-Дын (2008-06-24 15:34:00) [14]
> Игорь Шевченко © (24.06.08 15:29) [2]
Terminate, на самом деле, у меня по другому определено.
Это просто пример.
В реальном проекте такой вид:
procedure TThrSockClient.Terminate;
begin
FTerminated := True;
PostThreadMessage(ThreadId,WM_QUIT,0,0);
end;
Игорь Шевченко (2008-06-24 15:29:00) [15]
> 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:14:00) [16]Сорри, не тот тег выставил.
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.