#delphi #overloading
#delphi #перегрузка
Вопрос:
В Delphi я могу сделать это:
Type
TFourCC = Array[0..3] of AnsiChar;
Function Func(Param : TFourCC) : Boolean;
begin
{ ... }
end;
Func('ABCD'); // I can pass this as literal text without problems
Теперь я хочу сделать этот параметр необязательным.
Function Func(Param : TFourCC = 'ABCD') : Boolean;
begin
{ ... }
end;
Теперь компилятор выдает мне ошибку: E2268 Parameters of this type cannot have default values
Хорошо, поэтому я подумал, что перегрузка функции должна сработать…
Function Func : Boolean; overload;
begin
{ ... }
end;
Function Func(Param : TFourCC) : Boolean; overload;
begin
{ ... }
end;
Func('ABCD'); // This line that worked in first example now gives an error
К сожалению, Delphi это тоже не нравится. Там, где он сначала принял параметр как TFourCC
типизированную переменную, теперь он выдает мне E2250 There is no overloaded version of 'Func' that can be called with these arguments
.
Я прошу не согласиться с тем, что говорит мне эта ошибка, то же самое работало, когда оно не было перегружено.
Может кто-нибудь объяснить мне логику, стоящую за этим, и, возможно, решение? Я бы хотел сохранить TFourCC
таким, какой он есть (не строковый тип), это значительно упрощает обработку чтения и записи. Я предпочитаю не присваивать его переменной, прежде чем передавать ее, потому что функция будет использоваться много..
Комментарии:
1. Могу я спросить, какие точные свойства
TFourCC
типа вы хотели бы сохранить?2. @AndreasRejbrand Мне не нужен префикс длины байта, который имеет строка. Я не хочу, чтобы эти накладные расходы при чтении или записи в буфер или файл. И он должен быть читаемым человеком, поэтому использование 32-разрядного целочисленного типа также не идеально.
3. Хороший вопрос, компилятор ошибается
Ответ №1:
К сожалению, в настоящее время система типов работает именно так.
Но хорошей новостью является то, что вы можете творить чудеса с записями и перегрузкой оператора. Например, с
type
TFourCC = record
strict private
function GetChar(Index: Integer): AnsiChar;
procedure SetChar(Index: Integer; const Value: AnsiChar);
public
class operator Implicit(AValue: AnsiString): TFourCC;
class operator Implicit(AValue: TFourCC): AnsiString;
class operator Equal(a, b: TFourCC): Boolean;
class operator NotEqual(a, b: TFourCC): Boolean;
property Chars[Index: Integer]: AnsiChar read GetChar write SetChar; default;
case Boolean of
False: (AnsiChars: array[0..3] of AnsiChar);
True: (Data: Cardinal)
end;
implementation
{ TFourCC }
class operator TFourCC.Implicit(AValue: AnsiString): TFourCC;
begin
if Length(AValue) <> 4 then
raise Exception.Create('Not a valid TFourCC string.');
Result.Data := PCardinal(@AValue[1])^;
end;
class operator TFourCC.Implicit(AValue: TFourCC): AnsiString;
begin
SetLength(Result, 4);
PCardinal(@Result[1])^ := AValue.Data;
end;
class operator TFourCC.Equal(a, b: TFourCC): Boolean;
begin
Result := a.Data = b.Data;
end;
class operator TFourCC.NotEqual(a, b: TFourCC): Boolean;
begin
Result := a.Data <> b.Data;
end;
function TFourCC.GetChar(Index: Integer): AnsiChar;
begin
Result := AnsiChars[Index];
end;
procedure TFourCC.SetChar(Index: Integer; const Value: AnsiChar);
begin
AnsiChars[Index] := Value;
end;
вы получаете все эти преимущества:
procedure TForm1.FormCreate(Sender: TObject);
var
x: TFourCC;
begin
x := 'FINE'; // implicit conversion from string
ShowMessage(x); // implicit conversion to string
x[0] := 'D'; // can access parts for writing (without explicit member)
ShowMessage(x);
ShowMessage(x[0]); // can access parts for reading (without explicit member)
ShowMessage(x.Data.ToString); // can access underlying storage as a 32-bit integer
end;
И теперь вы можете сделать
procedure f(A: TFourCC); overload;
begin
ShowMessage(A);
end;
procedure f; overload;
begin
ShowMessage('ABCD');
end;
К сожалению, я очень спешу прямо сейчас, поэтому я не могу перепроверить правильность или прокомментировать дальше прямо сейчас!
Комментарии:
1. Спасибо! Кажется, что требуется много усилий для чего-то относительно простого, но это, несомненно, делает свое дело.
2. Мне также нужно иметь возможность сравнивать FOURCCS, поэтому для моей цели я добавил операторы классов
Equal
иNotEqual
.3. @Pantalaimon: Да, эти дополнения очень естественны.
4. Было бы неплохо добавить операторы класса для преобразования в / из String / Char, чтобы избежать предупреждения о неявных приведениях.
5. @fpiette: Действительно, записи с перегрузкой оператора — это очень гибкая и мощная функция, которая позволяет вам адаптировать тип к вашим собственным потребностям.