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

Вниз

Как создать свой конструктор с другими параметрами?   Найти похожие ветки 

 
MadLesS ©   (2005-03-03 21:06) [0]

Я создаю класс на основе TComponent и переписываю у него конструктор:
constructor Create(AOwner: TComponent; MaskName, SpriteName, CoordName: String); override
Но цомпилятор матерится, типа у него параметры отличаются.
Я тогда вместо override нарисовал overload, а он мне, буржуй иностранный, говорит, что метод предка будет скрыт, хоть и компилюкает. Возможно ли этого вообще избежать?


 
Anatoly Podgoretsky ©   (2005-03-03 21:08) [1]

Никакого различия с обычным, должно быть только разное имя


 
MadLesS ©   (2005-03-03 21:16) [2]

Это в каком смысле с обычным? А если я не хочу разых имён. Возможно ли переопределить метод предка изменив его параметры и чтобы не появлялись варнинги?


 
Anatoly Podgoretsky ©   (2005-03-03 21:18) [3]

А так
constructor Имя(формальные параметры); модификаторы;


 
MadLesS ©   (2005-03-03 21:22) [4]

Извините за беспросветность. Вы имеете ввиду задать ему Имя, отличное от Create? Если так, то я хочу именно чтобы было Create. Такое реально?


 
Anatoly Podgoretsky ©   (2005-03-03 21:25) [5]

А зачем тебе именно Сreate?
Почему не устраивает MyСreate?
По поводу хотелки 0 вам шашечки или ехать?


 
MadLesS ©   (2005-03-03 21:30) [6]

Ну пасиба за разъяснения. Просто я хотел, чтобы всё было красиво что-ли. Но по вашим ответам ясно, что не судьба. Будем знать


 
Anatoly Podgoretsky ©   (2005-03-03 21:38) [7]

Более красиво, когда разные имена, строго отвечающие за особенности конструкторов.


 
Anatoly Podgoretsky ©   (2005-03-03 21:39) [8]

Как мне кажется, для перегрузки и для виртуальности оба модификатора должны использоваться одновременно, но это требует проверки.


 
jack128 ©   (2005-03-03 21:54) [9]

constructor Create(AOwner: TComponent; MaskName, SpriteName, CoordName: String); reintroduce; естественнно о виртуальности(в частности о использовании в дезин тайм) можно забыть ;-)


 
Юрий Зотов ©   (2005-03-03 23:40) [10]

> MadLesS ©   (03.03.05 21:06)  
> вместо override нарисовал overload, а он мне, буржуй
> иностранный, говорит, что метод предка будет скрыт,
> хоть и компилюкает. Возможно ли этого вообще избежать?

constructor Create(...); reintroduce; overload;
reintroduce - посмотрите в справке.

> jack128 ©   (03.03.05 21:54) [9]
> естественнно о виртуальности (в частности о использовании
> в дезин тайм) можно забыть

Вот такой код, по крайней мере, спокойно компилится. В работе не проверял, но почему-то надеюсь, что и работать будет.
:о)

type
 TForm1 = class(TForm)
 public
   constructor Create(AOwner: TComponent); overload; override;
   constructor Create(I: integer); reintroduce; overload; virtual;
 end;

 TForm2 = class(TForm1)
 public
   constructor Create(I: integer); override;
 end;

constructor TForm1.Create(I: integer);
begin
 inherited Create(Application)
end;

constructor TForm1.Create(AOwner: TComponent);
begin
 Create(0)
end;

constructor TForm2.Create(I: integer);
begin
 inherited
end;


Получаем новую виртуальную цепочку, как ответвление от прежней?
:о)


 
jack128 ©   (2005-03-04 00:43) [11]

А толку от неё?? Мы ведь не можем в дезин тайм создать форму с I отличным от нуля. Ну то есть толк может и есть, если есть какое то чаще всего используемое значение параметра I..


 
Юрий Зотов ©   (2005-03-04 01:34) [12]

> jack128 ©   (04.03.05 00:43) [11]

> толк может и есть, если есть какое то чаще всего используемое
> значение параметра I.

Например, задаваемое в виртуальном классовом методе. Еще больше виртуальности получается, однако...
:о)

Да ведь и пример конструктора с Integer - это всего лишь пример, на деле же можно делать что угодно. Например, растроить или расчетверить или рас_N_рить цепочку - и все одним и тем же способом. И все, вроде как, вполне виртуально.

Интересные возможности здесь открываются, по-моему.


 
default ©   (2005-03-04 01:37) [13]

reintroduce;
нужен ли?
я давно ставил его смотрел CPU(потому как на деле разницы не видел), не ставил - смотрел CPU - одна фигня


 
GuAV ©   (2005-03-04 01:41) [14]

default ©   (04.03.05 1:37) [13]

Он только warning убирает.

Юрий Зотов ©   (04.03.05 1:34) [12]
Интересные возможности здесь открываются, по-моему.


Всё же непонятно какие дополнительные вохможности открываюся при сохдании компонента в designtime и чтении из dfm. Совершенно неважно какие там конструкторы, вызовется TComponent.Create;


 
default ©   (2005-03-04 01:44) [15]

GuAV ©   (04.03.05 01:41) [14]
сурьёзная весч:-)


 
Юрий Зотов ©   (2005-03-04 01:52) [16]

> GuAV ©   (04.03.05 01:41) [14]
> вызовется TComponent.Create;

Ну, все же не TComponent.Create, а TМой_класс.Create(Owner). Исходный конструктор ведь виртуальный.

А вот потом начинаются интересные вещи. Этот исходный конструктор вызывает любой другой конструктор (см. код), причем тоже виртуальный - и рулим, как хотим.

Выходит, обхитрили мы IDE, все же.


 
GuAV ©   (2005-03-04 02:10) [17]

Юрий Зотов ©   (04.03.05 1:52) [16]
Этот исходный конструктор вызывает любой другой конструктор


Конструктор вызванный из другого конструктора ведёт себя как обычный метод. Могли бы объявить обычный метод, вызываем его из конструктора

> и рулим, как хотим.


Нифига мы ни обхитрили, ни IDE, ни загрузку из dfm.
Кстати, а есть ли способ отличить вызов конструкора (именно конструктора) из IDE и при загрузки ?


 
GuAV ©   (2005-03-04 02:15) [18]

GuAV ©   (04.03.05 2:10) [17]
Кстати, а есть ли способ отличить вызов конструкора (именно конструктора) из IDE и при загрузки ?

Т.е. работает ли ComponentState в конструкторе ?


 
jack128 ©   (2005-03-04 10:31) [19]

GuAV ©   (04.03.05 2:15) [18]
Т.е. работает ли ComponentState в конструкторе ?

да, конечно. например

function TReader.ReadComponent(Component: TComponent): TComponent;
...
 procedure CreateComponent;
 var
   ComponentClass: TComponentClass;
 begin
   ...
       Result := TComponent(ComponentClass.NewInstance);
       if ffInline in Flags then
       begin
         Include(Result.FComponentState, csLoading);
         Include(Result.FComponentState, csInline);
       end;
       try
         Result.Create(Owner);
       except
 end;
....


 
jack128 ©   (2005-03-04 10:44) [20]

Юрий Зотов ©   (04.03.05 1:52) [16]
Например, задаваемое в виртуальном классовом методе

Выходит, обхитрили мы IDE, все же.

Обхитрили, да не совсем.  Мы не можем передать в конструктор значение I, которое задал программист в дезин тайм. Значение, заданное в дезин тайм можно записать в dfm(через DefineProperties), но ПРОЧИТАТЬ его во время выполнения конструктора мы не можем(точнее можем, но это нужно будет вручную парсить дфм"ку из ресурсов).


 
Юрий Зотов ©   (2005-03-04 13:05) [21]

> jack128 ©   (04.03.05 10:44) [20]

> Мы не можем передать в конструктор значение I, которое задал
> программист в дезин тайм.

И не нужно. Любой конструктор (в том числе, родной) для таких вещей и не предназначен, он выполняется до чтения DFM.

Суть здесь не в этом, а в том, что несмотря на введение нового конструктора виртуальность мы все же сохранили (раз) и заставили IDE вызывать наш конструктор (два). Что и требовалось.


 
GuAV ©   (2005-03-04 14:06) [22]

Юрий Зотов ©   (04.03.05 13:05) [21]
Суть здесь не в этом, а в том, что несмотря на введение нового конструктора виртуальность мы все же сохранили (раз) и заставили IDE вызывать наш конструктор (два). Что и требовалось.


Тогда при чём тут конструктор ? Это же можно було получить добавив дополнительный виртуальный метод.

Если конструктор вызывается из другого конструкора этого же класса, он ведёт себя как обычный метод.

Мы бы обхитрили IDE если бы заставили её сразу вызывать новый конструктор для создания компонента.


 
Юрий Зотов ©   (2005-03-04 15:38) [23]

> GuAV ©   (04.03.05 14:06) [22]

> Это же можно було получить добавив дополнительный
> виртуальный метод.

type
 TComp = class(TComponent)
 public
   constructor Create(AOwner: TComponent); overload; override;
   constructor Create(AOwner: TComponent; I: integer); reintroduce; overload; virtual;
 end;

 TCompClass = class of TComp;

 TChildComp = class(TComp)
 public
   constructor Create(AOwner: TComponent; I: integer); override;
 end;

 TGrandChildComp = class(TChildComp)
 public
   constructor Create(AOwner: TComponent; I: integer); override;
 end;

constructor TComp.Create(AOwner: TComponent);
begin
 ShowMessage("Родной конструктор TComp");
 Create(AOwner, 0)
end;

constructor TComp.Create(AOwner: TComponent; I: integer);
begin
 ShowMessage("Новый конструктор TCоmp");
 inherited Create(AOwner);
end;

constructor TChildComp.Create(AOwner: TComponent; I: integer);
begin
 ShowMessage("Новый конструктор TChildCоmp")
end;

constructor TGrandChildComp.Create(AOwner: TComponent; I: integer);
begin
 ShowMessage("Новый конструктор TGrandChildCоmp")
end;

procedure TForm1.ButtonsClick(Sender: TObject);
var
 CompClass: TCompClass;
begin
 case TButton(Sender).Tag of
  `1: CompClass := TComp;
   2: CompClass := TChildComp;
   3: CompClass := TGrandChildComp
   else
     CompClass := nil
 end;
 if CompClass <> nil then
   CompClass.Create(Self, 0)
end;

Строка, выделенная жирным - это и цель, ради которой все затевалось. Сможете получить то же самое простым добавлением нового виртуального метода?

> Если конструктор вызывается из другого конструкора этого же
> класса, он ведёт себя как обычный метод

Не так. Он ведет себя как обычный метод, если вызывается через ссылку на экземпляр класса, а не на класс. И не имеет никакого значения, откуда этот вызов производится.

> Мы бы обхитрили IDE если бы заставили её сразу вызывать новый
> конструктор для создания компонента.

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

А уж каким там образом будет запускаться наша цепочка - сразу, или опосредовано - нам это, в общем-то, абсолютно по барабану.


 
GuAV ©   (2005-03-04 22:07) [24]


> Строка, выделенная жирным - это и цель, ради которой
> все затевалось. Сможете получить то же самое простым
> добавлением нового виртуального метода?


ОК, согласен что такое поведение нельзя было получить добавлением виртуального метода (разве что class methodа).

Не согласен что есть разница между добавлением конструктора и обычного метода при создании компонента из dfm или кидании на форму.


> Не так. Он ведет себя как обычный метод, если
> вызывается через ссылку на экземпляр класса, а не на
> класс.


Ну да, вызов используя ссылку на экземпляр класса self подразуевался.


> И не имеет никакого значения, откуда этот вызов
> производится.

Всё же, разница есть.

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

Это примерно как пытаться объявить свой деструктор - непосредственно вызывать его можно, однако при ислючении в конструкторе, при вызове TObject.Free и в других случаях будет вызван destructor destroy - VCL и RTL другие деструкторы по барабану.


 
Юрий Зотов ©   (2005-03-05 00:33) [25]

> GuAV ©   (04.03.05 22:07) [24]

> ОК, согласен что такое поведение нельзя было получить
> добавлением виртуального метода (разве что class methodа).

Даже и class метода - все равно нельзя. Именно созданием новой цепочки виртуальных конструкторов.

> Всё же, разница есть.

Все же, разницы нет. Если конструктор вызывается через ссылку на экземпляр, то это просто вызов метода. Откуда бы он ни вызывался - хоть изнутри, хоть снаружи. А если через ссылку на класс, то это - создание нового экземпляра. Тоже откуда бы он ни вызывался - хоть изнутри, хоть снаружи.

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

Плз, не объясняйте мне азбуку в третий раз. Сорри за самоцитату, но: "Наша цель состояла ... в том, чтобы получить новую цепочку виртуальных конструкторов - и мы этой цели достигли, причем совершенно корректным способом. Вот что главное. А уж каким там образом будет запускаться наша цепочка - сразу, или опосредовано - нам это, в общем-то, абсолютно по барабану".

В противоречие [9], мы все же создали механизм, который реально работает, понимате? При этом еще и абсолютно не нарушая канонов альма-матер.

В run-time мы можем запустить этот механизм напрямую, в design-time он запускается опосредовано, через стандартный конструктор - но в любом случае он гарантированно запускается и в любом случае дает нужный результат.

Теория соблюдена, практика достигнута. Что ж еще?


 
GuAV ©   (2005-03-05 01:05) [26]

Юрий Зотов ©   (05.03.05 0:33) [25]
Даже и class метода - все равно нельзя.

Класс метод вполне может вызвать конструктор и проризведя манипуляции над вновь созданным объектом вернуть ссылку на него, не так ли ?

Юрий Зотов ©   (05.03.05 0:33) [25]
Все же, разницы нет.

Разницу можно видеть в окне CPU.
Разница в том что будет при исключении в конструкторе.


 
Юрий Зотов ©   (2005-03-05 01:49) [27]

> GuAV ©   (05.03.05 01:05) [26]

> Класс метод вполне может вызвать конструктор и проризведя
> манипуляции над вновь созданным объектом вернуть ссылку на
> него, не так ли ?

Может. НЕ класс-метод - тоже может. И что с того?

> Разницу можно видеть в окне CPU.
> Разница в том что будет при исключении в конструкторе.

Разницу, определяемую местом вызова?


 
GuAV ©   (2005-03-05 02:13) [28]

Юрий Зотов ©   (05.03.05 1:49) [27]
Разницу, определяемую местом вызова?


Да.


 
Юрий Зотов ©   (2005-03-05 15:06) [29]

Именно местом вызова? Не способом, а именно местом?

Хорошо, давайте так - не будем голословными. Код, подтверждающий мои слова я уже привел. Приведите код, подтверждающий Ваши.


 
GuAV ©   (2005-03-05 15:47) [30]

Юрий Зотов ©   (05.03.05 15:06) [29]

Уже обсуждалось.

type
 TMyObject = class
   constructor SomeConstructor;
   procedure SomeMethod;
 end;

{ TMyObject }

constructor TMyObject.SomeConstructor;
begin
 Create; // этот вызов конструктора НЕ приведёт к вызову System._ClassCreate из него
end;

procedure TMyObject.SomeMethod;
begin
 Create; // этот вызов конструктора приведёт к вызову System._ClassCreate из него
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 with TMyObject.SomeConstructor do
 try
   SomeMethod;
 finally
   Free;
 end;
end;


Разница проявится в том, что исключение в конструкторе вызванном из другого конструктора не приведёт к вызову деструтора destroy.


 
Юрий Зотов ©   (2005-03-05 18:50) [31]

> GuAV ©   (05.03.05 15:47) [30]

Про вызов System._ClassCreate Вы правильно написали, только факт такого вызова сам по себе еще ничего не означает. Поскольку он может привести к созданию нового объекта, а может и не привести (там JL имеется). Вот иллюстрация (Ваш же код, только еще замещен метод NewInstance).

type
 TMyObject = class
   class function NewInstance: TObject;  override;
   constructor SomeConstructor;
   procedure SomeMethod;
 end;

var
 InstanceCount: integer = 0;

class function TMyObject.NewInstance: TObject;
begin
 Result :=  inherited NewInstance;
 Inc(InstanceCount)
end;

constructor TMyObject.SomeConstructor;
begin
 Create
end;

procedure TMyObject.SomeMethod;
begin
 Create
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 InstanceCount := 0;
 Caption := "";
 with TMyObject.SomeConstructor do
 try
   ShowMessage(IntToStr(InstanceCount)); // Получаем 1.
   SomeMethod;
   ShowMessage(IntToStr(InstanceCount))  // И снова 1.
 finally
   Free
 end
end;

Причина легко выясняется трассировкой System._ClassCreate (только сначала закомментируйте ShowMessage, а то долго будет).

> Разница проявится в том, что исключение в конструкторе
> вызванном из другого конструктора не приведёт к вызову
> деструтора destroy.


А вот что говорят по этому поводу классики и апологеты. По сути, не вдаваясь в детали реализации.

Конструктор может быть вызван двумя способами - через ссылку на класс (аналогично классовому методу) и через ссылку на экземпляр класса (аналогично обычному методу).

В первом случае компилятор строит неявный префиксный код, создающий новый экземпляр класса, а вызов самого конструктора обрамляет неявным же блоком try-except, помещая в секцию except код уничтожения только что созданного объекта и код повторного возбуждения исключения.

Во втором случае компилятор строит вызов конструктора, как вызов обычного метода. При этом новый экземпляр класса не создается и, соответственно, никакого дополнительного кода не строится.

Таким образом, если верить классикам и апологетам, то при исключении в конструкторе деструктор НЕ будет вызван, если этот конструктор вызывался через ссылку на ЭКЗЕМПЛЯР класса, а не на класс. Все равно откуда.

Соответственно, при исключении в конструкторе деструктор БУДЕТ вызван, если этот конструктор вызывался через ссылку на КЛАСС, а не на экземпляр класса. Тоже все равно откуда.

То есть, важно не ОТКУДА, а КАК вызывался конструктор. Что и подверждает приведенный выще код.

Первый вызов ShowMessage показывает 1 потому, что конструктор SomeConstructor был вызван через ссылку на класс - соответственно, был вызван NewInstance и создан новый экземпляр объекта. Как видим, вызов конструктора Create внутри SomeConstructor нового объекта не создает и, соответственно, NewInstancе НЕ вызывает. Потому что Create был вызван через ссылку не на класс, а на экземпляр класса Self. Как видим, все соответствует словам классиков.

Второй вызов ShowMessage снова показывает 1 потому, что в методе SomeMethod конструктор Create снова был вызван через ссылку не на класс, а на экземпляр класса Self. Соответсвенно, NewInstance не вызывается и счетчик не увеличивается - остается 1. Как видим, снова все соответствует словам классиков.

Теперь об автоматическом вызове деструктора. Добавляем к TMyObject такой код:

constructor Create;
destructor Destroy; override;

constructor TMyObject.Create;
begin
 inherited;
 raise Exception.Create("")
end;

destructor TMyObject.Destroy;
begin
 inherited;
end;

И ставим в деструкторе точку останова. После чего моментально убеждаемся, что деструктор вызывается именно в результате вызова Create из SomeConstructor - что впрямую противоречит Вашему утверждению "исключение в конструкторе вызванном из другого конструктора не приведёт к вызову деструтора Destroy". Приводит, как видите, еще как приводит.

И понятно, почему это так. Потому что классики снова правы и вызов TMyObject.SomeConstructor компилятор неявно построил по такой схеме:

NewObject := System._ClassCreate(...);
try
 NewObject.SomeConstructor // Здесь получаем исключение
except
 NewObject.Free; // И, естественно, приходим сюда.
 raise
end;

Так как - будем спорить дальше, или все же согласимся с апологетами?


 
GuAV ©   (2005-03-05 20:19) [32]


> Соответственно, при исключении в конструкторе
> деструктор БУДЕТ вызван, если этот конструктор
> вызывался через ссылку на КЛАСС, а не на экземпляр
> класса. Тоже все равно откуда.


Вне сомнения.


> Таким образом, если верить классикам и апологетам, то
> при исключении в конструкторе деструктор НЕ будет
> вызван, если этот конструктор вызывался через ссылку
> на ЭКЗЕМПЛЯР класса, а не на класс. Все равно откуда.

А вот тут поспорим.
Для простоты можно без всяких CPU и F7, просто убедитесь в появлении сообщения Destroyed и ошибке при попытке повторно освободить.

type
TMyObject = class
  constructor SomeConstructor;
  destructor Destroy; override;
end;

{ TMyObject }

destructor TMyObject.Destroy;
begin
 ShowMessage("Destroyed");
end;

constructor TMyObject.SomeConstructor;
begin
 raise Exception.Create("test");
end;

procedure TForm1.Button1Click(Sender: TObject);
var Inst: TMyObject;
begin
 Inst := TMyObject.Create;
 try
   Inst.SomeConstructor;
 except
   Application.HandleException(Self);
 end;
// Inst.Free //приведёт к AV
end;


> И ставим в деструкторе точку останова. После чего
> моментально убеждаемся, что деструктор вызывается
> именно в результате вызова Create из SomeConstructor -
> что впрямую противоречит Вашему утверждению
> "исключение в конструкторе вызванном из другого
> конструктора не приведёт к вызову деструтора Destroy".
> Приводит, как видите, еще как приводит

Оно приводит к вызову деструтора Destroy только потому что попадает в конструтор SomeConstructor. Если его обоработать в SomeConstructor - то не приведёт.
Если бы исключение в Create вызванном таким образом приводило бы к вызову деструктора, мы бы имели два вызова деструктора - один из-зи исключения в Create, второй из-за исключения в SomeConstructor.



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

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

Наверх





Память: 0.58 MB
Время: 0.079 c
14-1129697671
boalse
2005-10-19 08:54
2005.11.13
Час суда и т.п.


2-1129725970
Dinny
2005-10-19 16:46
2005.11.13
Редактирование индексированных таблиц


4-1126252766
Андрей Жук
2005-09-09 11:59
2005.11.13
Работа с национальными клавиатурами


2-1129821214
xVEst
2005-10-20 19:13
2005.11.13
Проблема с компонентом Rave


2-1129910821
Spinu Oleg
2005-10-21 20:07
2005.11.13
Указатели





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский