|
Вопрос # 3 062/ вопрос открыт / |
|
Приветствую, уважаемые эксперты!
У меня такая проблема: я первый раз пытаюсь написать компонент (а вместе с ним и новый класс с конструктором), почитал несколько статей по созданию компонентов, так же почитал про классы. Решил для начала создать легкий компонент, который управляет лог-файлом. Вот основные проблемы:
1) При компиляции выдается ошибка:
[Error] LogMaster.pas(21): Declaration of 'Create' differs from previous declaration (код в приложении), в чем тут дело?
2) немогли бы вы по подробней рассказать когда следует использовать override, overload?
Приложение: Переключить в обычный режим- unit LogMaster;
-
- interface
-
- uses
- SysUtils, Classes, Forms;
-
- type
- TLogMaster = class(TComponent)
- procedure AddEvent(Event: string);
- function RemoveLog: boolean;
- private
- LogFile: text;
- T: string;
- { Private declarations }
- protected
- { Protected declarations }
- public
- { Public declarations }
- published
- constructor Create(FileName: string); override;
- { Published declarations }
- end;
-
- procedure Register;
-
- implementation
-
- procedure Register;
- begin
- RegisterComponents('Log Master', [TLogMaster]);
- end;
-
- constructor TLogMaster.Create(FileName: string);
- var D: string;
- begin
- D:=DateToStr(Now);
- T:=TimeToStr(Now);
- FileName:=FileName+'_log.txt';
- AssignFile(LogFile, FileName);
- try
- Rewrite(LogFile);
- Write(LogFile,'------ File info -----'+#13#10);
- Write(LogFile,'## Log File From "'+ExtractFileName(Application.ExeName)+'"'+#13#10);
- Write(LogFile,'## Start Date: '+D+#13#10);
- Write(LogFile,'## Start Time: '+T+#13#10);
-
- Write(LogFile,'------ Start Log -----'+#13#10+#13#10+#13#10);
- CloseFile(LogFile);
- except
- end;
- end;
-
- procedure TLogMaster.AddEvent(Event: string);
- begin
- try
- Append(LogFile);
- Write(LogFile,T+': '+Event+#13#10);
- except
- end;
- end;
-
- function TLogMaster.RemoveLog: boolean;
- begin
- end;
-
- end.
 |
Вопрос задал: IlluminatI (статус: 2-ой класс)
Вопрос отправлен: 3 августа 2009, 21:19
Состояние вопроса: открыт, ответов: 3.
|
Ответ #1. Отвечает эксперт: min@y™
Как говорится, найди 10 отличий и тогда всё поймёшь.
Какой смысл делать такой класс компонентом?
Приложение: Переключить в обычный режим- unit LogMaster;
-
- interface
-
- uses
- SysUtils, Classes, Forms;
-
- type
- TLogMaster = class(TComponent)
- procedure AddEvent(Event: string);
- function RemoveLog: boolean;
- private
- LogFile: text;
- T: string;
-
- protected
- { Protected declarations }
- public
- { Public declarations }
- published
- constructor Create(AOwner: TComponent; const FileName: string); reintroduce;
-
- end;
-
- procedure Register;
-
- implementation
-
- procedure Register;
- begin
- RegisterComponents('Log Master', [TLogMaster]);
- end;
-
- constructor TLogMaster.Create(AOwner: TComponent; const FileName: string);
- var D: string;
- begin
- inherited Create(AOwner);
-
- D:=DateToStr(Now);
- T:=TimeToStr(Now);
-
-
-
-
- AssignFile(LogFile, FFileName);
- {$I-}
- Rewrite(LogFile);
- Write(LogFile,'------ File info -----' + #13#10);
- Write(LogFile,'## Log File From "' + ExtractFileName(Application.ExeName)+'"'+#13#10);
- Write(LogFile,'## Start Date: ' + D + #13#10);
- Write(LogFile,'## Start Time: ' + T + #13#10);
-
- Write(LogFile,'------ Start Log -----'+#13#10+#13#10+#13#10);
- CloseFile(LogFile);
- {$I+}
- if IOError <> 0
- then raise;
- end;
-
- procedure TLogMaster.AddEvent(Event: string);
- begin
- try
- Append(LogFile);
- Write(LogFile,T+': '+Event+#13#10);
- except
- end;
- end;
-
- function TLogMaster.RemoveLog: boolean;
- begin
-
- end;
-
- end.
 |
Ответ отправил: min@y™ (статус: Доктор наук)
Время отправки: 3 августа 2009, 21:42
Оценка за ответ: 4
Комментарий к оценке: смысла нет, но есть желание научится) от простого к сложному)
|
Ответ #2. Отвечает эксперт: Вадим К
Здравствуйте, IlluminatI!
Давайте вначале посмотрим, почему данный код плохой. Вы создаете компонент, который наверно захотите поставить на форму. А для этого среда делфи должна уметь вызвать конструктор. Она знает, что все компоненты, которые можно поставить на форму, имеют конструктор с определёнными параметрами. Ваший же конструктор она вызвать не сможет. Она банально не знает, что передать в параметр Filename. Параметры конструктора должны совпадать с параметрами конструктора предка. Да, в целом, конструктор дочернего класса может отличаться (более того, их может быть много), но тут мы имеем дело с компонентом. Поэтому либо следуем по правилам делфи, либо делаем класс, который не будет компонентом. Можно создать два конструктора, один для делфи, другой для себя, но это отдельная история.
А что же делать с параметром FileName? либо инициализировать чем то по умолчанию, либо просто не давать работать, пока свойство не будет установлено. А для установки свойства делаем свойство/метод.
замечания к коду
Write(LogFile,'------ File info -----'+#13#10);
а рассказывали ли вам о процедуре Writeln? Она сама добавляет перевод строки. То есть надо так
WriteLn(LogFile,'------ File info -----');
Хотя в предыдущей строке можно было и плюсик не писать, будет работать:)
AddEvent - открыть файл отрыли, а кто закрывать будет за собой?
overload
иногда хочеться иметь два-три метода с одинаковыми именами, но разными входными параметрами. Но компилятор ругается, если объявить несколько методов с одинаковым именем. И для того, что бы успокоить компилятор, дать ему понять, что это мы хотим так, и существует ключевое слово overload.
override
Это ключевое слово нужно, что бы указать компилятору, что мы перекрываем виртуальный метод предка. Мне кажеться, что это синтаксический сахар и можно было бы обойтись без него, но...
то min@y™
reintroduce;... да, выход конечно. но будет приятное исключение, когда компонент на форму ставить будем:))
код с IOResult с последующей генерацией исключения... try except чудно умеет их и сам перехватывать.
 |
Ответ отправил: Вадим К (статус: Академик)
Время отправки: 3 августа 2009, 22:02
Оценка за ответ: 5
Комментарий к оценке: Спасибо, буду разбираться)
|
Ответ #3. Отвечает эксперт: Amidamaru
Здравствуйте, IlluminatI!
Думаю стоит начать с override и overload.
overload используется для функций или методов имеющих одно и тоже имя но различные параметры.
пример использования overload - функция inttostr() которая может принимать в качестве параметра integer и int64.
override используется в при создании нового класса, когда необходимо изменить наследуемый метод.
при этом описание метода, на котором используется override, должно быть идентично описанию этого метода у "предка".
В этом у вас и ошибка.
конструктор Create у TComponent имеет вид:
constructor Create(AOwner: TComponent);
точно такоеже описание должно быть и у вас если вы хотите использовать override.
и ещё по мелочам у вас немало ошибок в коде.
В часности Filename: string лучше вынести как свойство и всё что выполняется в Create перенести в наследуемый метод Loaded;
Заходите какнибудь на IRC канал на dalnet, помогу. А сейчас советую только посмотреть примеры создания несложных компонентов.
 |
Ответ отправил: Amidamaru (статус: 4-ый класс)
Время отправки: 3 августа 2009, 22:04
|
Мини-форум вопроса
Всего сообщений: 7; последнее сообщение — 3 августа 2009, 23:01; участников в обсуждении: 3.
|
min@y™ (статус: Доктор наук), 3 августа 2009, 21:56 [#1]:
Вообще, хреновая идея. Написал бы потомок от TStringList да и всё.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
Вадим К (статус: Академик), 3 августа 2009, 22:04 [#2]:
TStringList в данном случае может будет идеей похуже. Потому что если приложение "резко упадет", то лог не будет сохранен и вся сущность лога коту под хвост.
Галочка "подтверждения прочтения" - вселенское зло.
|
|
Amidamaru (статус: 4-ый класс), 3 августа 2009, 22:09 [#3]:
2 min@y™ я думаю в данном случае лучше было бы использовать перегузку Loaded; а не reintroduce.
|
|
min@y™ (статус: Доктор наук), 3 августа 2009, 22:12 [#4]:
Цитата:
Потому что если приложение "резко упадет", то лог не будет сохранен и вся сущность лога коту под хвост.
Здарова, братская Украина!
А это как написать...
Я бы добавил такой метод ---> function TLogFile.Flush(): Boolean;
Ты ж понимаешь, что должно быть внутри этого метода.
Цитата:
код с IOResult с последующей генерацией исключения... try except чудно умеет их и сам перехватывать.
Да это ж я для примера.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
Вадим К (статус: Академик), 3 августа 2009, 22:27 [#5]:
"Да это ж я для примера." Зачем? зачем усложнять жизнь.
"function TLogFile.Flush(): Boolean;" ещё раз в лоб. И будешь сбрасывать после каждого добавления строки? или раз на десять? первый лишен смысла - так как тогда StringList не нужен. Второй - тоже, потому что если приложение упало, мы теряем несколько последних сообщений.
Ещё вопросы?
Галочка "подтверждения прочтения" - вселенское зло.
|
|
min@y™ (статус: Доктор наук), 3 августа 2009, 22:58 [#6]:
Цитата:
Ещё вопросы?
У меня их и не было.
Не надо писать программы, которые резко падают.
Ну что? неужели опять будем полемику разводить? Я пишу так, как мне удобно, и бесплатно делюсь своим опытом. Причём, не гарантируя, что мои методы правильные. Я расказываю, как я делаю, а не как надо на самом деле.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
|
|
Вадим К (статус: Академик), 3 августа 2009, 23:01 [#7]:
если бы программы не падали, то и логи не надо...
Галочка "подтверждения прочтения" - вселенское зло.
|
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|