Коварные Warnings
Предупреждения-warnings обладают гораздо более высоким уровнем опасности с точки зрения компилятора. История с абстрактным классом служит тому примером. Разберем еще несколько случаев возникновения warning'ов:
Return value of function 'VarCompare' might be undefined
Значение результата функции 'VarCompare' может быть неопределено.
Function VarCompare(Index1, Index2: Integer): Integer; Begin IF Index1 = Index2 Then Result:=0; IF Index1 < Index2 Then Result:=-1; IF Index1 > Index2 Then Result:=1; End; ‹——Return value of function 'VarCompare' might be undefined
|
Казалось бы, с точки зрения логики в тексте функции все верно. Перекрыты все возможные случаи и сообщение компилятора выглядит несколько неуместно. Но не стоит ждать от него слишком много, компилятор не может (да и не обязан) вникать в логику программы. Для того, чтобы избавиться от этого сообщения, было бы правильно переписать это код. Например, вот так:
Function VarCompare(Index1, Index2: Integer): Integer; Begin IF Index1 = Index2 Then Result:=0 Else IF Index1 < Index2 Then Result:=-1 Else Result:=1; End; |
В итоге и компилятор "отстанет", и код будет более читабельным. Это сообщение только на первый взгляд кажется безобидным, ниже приведен пример, в котором возникает аналогичное предупреждение и содержится реальная ошибка — если возникнет исключительная ситуация при открытии файла, результат функции, действительно, не будет определен. В итоге это скажется при выполнении программы, когда ошибки никто не будет ожидать.
Function ReadList( FileName : String) : Boolean ; Var Stream : TFileStream; Begin IF FileExists(FileName) Then Try Stream:=TFileStream.Create(FileName , fmOpenRead); // .....
Stream.Free; Result:=True; Except End Else Result:=False;
End;‹——Return value of function 'ReadList' might be undefined
|
Правильный вариант:
Function ReadList( FileName : String) : Boolean ; Var Stream : TFileStream; Begin IF FileExists(FileName) Then Try Stream:=TFileStream.Create(FileName , fmOpenRead); // .....
Stream.Free; Result:=True; Except Result:=False; End Else Result:=False;
End; |
Еще один пример коварного
warning'а:
Variable 'list' might not have been initialized
Переменная 'list' может быть не инициализирована.
Function SomethingList( Text : String) : Integer; Var list : TStringList; Begin IF Text <> '' Then Begin list:=TStringList.Create; list.CommaText:=Text; End;
// .... код
Result:=list.Count; ‹—— Variable 'list' might not have been initialized
list.Free; End; |
Совершенно справедливое замечание. Если во время работы программы в функцию будет передана пустая строка, нам обеспечен знаменитый Access violation.
Вернемся еще раз к примеру с определением собственных классов.
TExLists = class(TList) Public procedure Clear; ‹—— Method 'Clear' hides virtual method of base type 'TList'
End; |
Method 'Clear' hides virtual method of base type 'TList' Метод 'Clear' прячет виртуальный метод базового класса 'TList'. Эта ситуация буквально означает перекрытие виртуального метода родительского класса. То есть, в классе TExLists определен статический метод, имя которого совпадает с виртуальным методом родительского класса TList. Если в дальнейшем, от класса TExLists будут наследоваться, то метод Clear для этих наследников будет закрыт.
Правильный вариант:
TExLists = class(TList) Public procedure Clear; override; End; |
Точно также, как и в случае с hint'ами, существуют опции для отключения сообщений компилятора о предупреждениях — {$WARNINGS OFF}, и для их включения — {$WARNINGS ON}. И точно так же хочу обратить внимание на нежелательность использования этих опций без нужды. Молчание компилятора в этом случае не будет означать отсутствие проблемы :о)
Содержание раздела