Форум: "Компоненты";
Текущий архив: 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