Форум: "Начинающим";
Текущий архив: 2009.04.05;
Скачать: [xml.tar.bz2];
ВнизДинамический массив структур (record) как свойство класса. Найти похожие ветки
← →
SingleStranger (2009-02-11 13:19) [0]Как реализовать?
Меня интересует способ с простым доступом к любому полю структуры.
Что-то типа того:TRec = record
field1: integer;
field2: string;
end;
TSomeClass = class
private
FSRec: array of TRec;
function GetSRec(Index: Integer): TRec;
procedure SetSRec(Index: Integer; const Value: TRec);
public
function SRecAddNew: Integer;
function SRecAdd(Value: TRec): Integer;
property SRec[Index: Integer]: TRec read GetSRec write SetSRec;
end;
И доступ, чтобы был простым, примерно так:var
i: integer;
r: TRec;
begin
r.field1 := 1;
r.field2 := "aaa";
i := SomeClass.SRecAdd(r);
SomeClass.SRec[i].field2 := "bbb";
end;
или как-то так:var
i: integer;
begin
i := SomeClass.SRecAddNew();
SomeClass.SRec[i].field2 := "bbb";
end;
← →
clickmaker © (2009-02-11 13:39) [1]и в чем проблема?
← →
SingleStranger (2009-02-11 13:43) [2]
> clickmaker © (11.02.09 13:39) [1]
> и в чем проблема?
Помоему, "Left side cannot be assigned to", если не ошибаюсь. Я код-то переписал, но нынешний вариант, вообще не устраивает. Вот и решил спросить.
← →
Ega23 © (2009-02-11 13:44) [3]
TSomeClass = class
private
FSRec: array of TRec;
function GetSRec(Index: Integer): TRec;
procedure SetSRec(Index: Integer; const Value: TRec);
public
function SRecAdd(Value: TRec): Integer;
property SRec[Index: Integer]: TRec read GetSRec write SetSRec;
end;
function TSomeClass.GetSRec(Index: Integer): TRec;
begin
Result := FSRec[Index];
end;
procedure TSomeClass.SetSRec(Index: Integer; const Value: TRec);
begin
FSRec[Index].field1 := Value.field1;
FSRec[Index].field2 := Value.field2;
end;
function TSomeClass.SRecAdd(Value: TRec): Integer;
begin
SetLength(FSRec, Hight(FSRec) + 1);
SetSRec(Hight(FSRec), Value);
Result := Hight(FSRec);
end;
Что-то типа этого.
P.S. С динамическими массивами практически не работал, поэтому не уверен, как правильно отработаетprocedure TSomeClass.SetSRec(Index: Integer; const Value: TRec);
begin
FSRec[Index].field1 := Value.field1;
FSRec[Index].field2 := Value.field2;
end;
Возможно достаточноFSRec[Index] := Value;
Надо проверять.
← →
SingleStranger (2009-02-11 13:46) [4]
> SingleStranger (11.02.09 13:43) [2]
> Помоему, "Left side cannot be assigned to"
При доступе к полю структуры.
← →
Anatoly Podgoretsky © (2009-02-11 13:48) [5]> SingleStranger (11.02.2009 13:19:00) [0]
У тебя нет свойства SomeClass.SRec[i].field2
Или делай свойство или копируй во временную переменную.
← →
Ega23 © (2009-02-11 13:55) [6]Если честно, то я бы TRec сделал классом, а в TSomeClass либо TObjectList в привате организовал с методами доступа, либо сам TSomeClass от TObjectList унаследовал (это уже от логики зависит).
← →
SingleStranger (2009-02-11 13:55) [7]
> Anatoly Podgoretsky © (11.02.09 13:48) [5]
> > SingleStranger (11.02.2009 13:19:00) [0]У тебя нет свойства
> SomeClass.SRec[i].field2Или делай свойство или копируй во
> временную переменную.
Т.е.?var
i: integer;
r: TRec;
begin
i := 0;
r := SomeClass.SRec[i];
r.field2 := "bbb";
SomeClass.SRec[i] := r;
end;
Так? Это еже неудобно.
А проще не получится?
← →
SingleStranger (2009-02-11 13:55) [8]
> Anatoly Podgoretsky © (11.02.09 13:48) [5]
> > SingleStranger (11.02.2009 13:19:00) [0]У тебя нет свойства
> SomeClass.SRec[i].field2Или делай свойство или копируй во
> временную переменную.
Т.е.?var
i: integer;
r: TRec;
begin
i := 0;
r := SomeClass.SRec[i];
r.field2 := "bbb";
SomeClass.SRec[i] := r;
end;
Так? Это еже неудобно.
А проще не получится?
← →
Anatoly Podgoretsky © (2009-02-11 14:00) [9]> SingleStranger (11.02.2009 13:55:07) [7]
Тебе привели два решения, а ты губы морщишь.
Не нравится предложеные, тогда сделай функции присвоения и вызывай их.
← →
Anatoly Podgoretsky © (2009-02-11 14:01) [10]> SingleStranger (11.02.2009 13:55:08) [8]
Проще вариант со свойствами.
← →
SingleStranger (2009-02-11 14:10) [11]
> Anatoly Podgoretsky © (11.02.09 14:01) [10]
> Проще вариант со свойствами.
Это как? Массив свойств?
> Anatoly Podgoretsky © (11.02.09 14:00) [9]
> тогда сделай функции присвоения и вызывай их.
Если это единственный способ, то видимо придется. Хотя, если честно, мне он не нравится.
> Ega23 © (11.02.09 13:55) [6]
> ... я бы TRec сделал классом, а в TSomeClass
> либо TObjectList в привате организовал с методами доступа ...
Обдумывал и этот вариант, но как-то не хотелось городить класс для, вобщем-то, простой структуры. Это просто настроечная структура, там куча полей простого типа. Но может и над классом подумаю.
Есть еще варианты?
← →
Ega23 © (2009-02-11 14:20) [12]
> А проще не получится?
Вот проще (сугубо ИМХО):unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Contnrs;
type
TSomeClass = class (TObject)
private
FField1 : Integer;
FField2: string;
public
procedure Assign(source : TSomeClass);
property Field1 : Integer read FField1 write FField1;
property Field2 : string read FField2 write FField2;
end;
TSomeClassContainer = class (TObject)
private
FItems : TObjectList;
function GetCount: Integer;
function GetItem(Index: Integer): TSomeClass;
procedure SetItem(Index: Integer; const Value: TSomeClass);
public
constructor Create;
destructor Destroy; override;
function AddItem(Item : TSomeClass) : Integer;
procedure DeleteItem(Index : Integer);
procedure Clear;
property Items[Index : Integer] : TSomeClass read GetItem write SetItem;
property Count : Integer read GetCount;
end;
implementation
{ TSomeClass }
procedure TSomeClass.Assign(source: TSomeClass);
begin
FField1 := source.FField1;
FField2 := source.FField2;
end;
{ TSomeClassContainer }
function TSomeClassContainer.AddItem(Item: TSomeClass): Integer;
begin
Result := FItems.Add(Item);
end;
procedure TSomeClassContainer.Clear;
begin
FItems.Clear;
end;
constructor TSomeClassContainer.Create;
begin
FItems := TObjectList.Create(True);
end;
procedure TSomeClassContainer.DeleteItem(Index: Integer);
begin
FItems.Delete(Index);
end;
destructor TSomeClassContainer.Destroy;
begin
FItems.Free;
inherited;
end;
function TSomeClassContainer.GetCount: Integer;
begin
Result := FItems.Count;
end;
function TSomeClassContainer.GetItem(Index: Integer): TSomeClass;
begin
try
Result := TSomeClass(FItems.Items[i]);
except
Result := nil;
end;
end;
procedure TSomeClassContainer.SetItem(Index: Integer;
const Value: TSomeClass);
begin
TSomeClass(FItems.Items[Index]).Assign(Value);
end;
end.
В данном варианте контейнер спрятан в private и доступ к нему идёт через public-функции.
← →
Ega23 © (2009-02-11 14:25) [13]
type
TSomeClass = class (TObject)
private
FField1 : Integer;
FField2: string;
public
procedure Assign(source : TSomeClass);
property Field1 : Integer read FField1 write FField1;
property Field2 : string read FField2 write FField2;
end;
TSomeClassContainer = class (TObjectList)
private
function GetItem(Index: Integer): TSomeClass;
public
property Items[Index : Integer] : TSomeClass read GetItem;
end;
implementation
{ TSomeClass }
procedure TSomeClass.Assign(source: TSomeClass);
begin
FField1 := source.FField1;
FField2 := source.FField2;
end;
{ TSomeClassContainer }
function TSomeClassContainer.GetItem(Index: Integer): TSomeClass;
begin
Result := TSomeClass(inherited GetItem(Index));
end;
end.
Тут уже никаких "пряталок" в контейнере, всё на свой страх и риск.
← →
Ega23 © (2009-02-11 14:28) [14]
> но как-то не хотелось городить класс для, вобщем-то, простой
> структуры.
Какая разница? Что класс, что рекорд. Ну перепиши вместоTSomeRec = record
field1: integer;
field2: string;
end;
сделайTSomeRec = class
public
field1: integer;
field2: string;
end;
← →
SingleStranger (2009-02-11 14:29) [15]
> Ega23 © (11.02.09 14:20) [12]
Хм...
Проще некуда =)))))
И это из структурки из двух полей =)))) Впору новый юнит под эту структуру выделять =))
Но, всеравно спасибо. Если ничего не нарою, то воспользуюсь.
← →
Ega23 © (2009-02-11 14:32) [16]
> Хм...
> Проще некуда =)))))
> И это из структурки из двух полей =)))) Впору новый юнит
> под эту структуру выделять =))
смотри [13], там гораздо проще. Но в [12] можно сделать более безопасно. Например, с проверками диапазона Index. Чтобы он неList index out of bounds
выдавал, а что-нибудь другое.
Всё от логики зависит. Я и тот и другой методы использую, в зависимости от ситуации.
← →
Anatoly Podgoretsky © (2009-02-11 14:59) [17]> SingleStranger (11.02.2009 14:10:11) [11]
А что тебя смущает, у тебя же уже есть одно индексное свойство, почему бы не добавить еще два.
← →
SingleStranger (2009-02-11 15:24) [18]
> Anatoly Podgoretsky © (11.02.09 14:59) [17]
> А что тебя смущает
Если честно, то не понимаю реализации.
← →
Sapersky (2009-02-11 15:36) [19]Самый простой и быстрый (но наименее расширяемый и безопасный) вариант:
TRecArray = array of TRec;
TSomeClass = class
private
FSRec: TRecArray;
public
property SRec: TRecArray read FSRec;
end;
← →
Anatoly Podgoretsky © (2009-02-11 15:45) [20]> SingleStranger (11.02.2009 15:24:18) [18]
А не надо реализовывать неверные решения, сделай класс.
← →
MsGuns © (2009-02-11 16:02) [21]Чтобы пожарить яичницу непременно надо завести птицефабрику или пихание классов куда попало во имя самих классов - отсюда и косяки с граблями
← →
Ega23 © (2009-02-11 16:04) [22]
> Чтобы пожарить яичницу непременно надо завести птицефабрику
> или пихание классов куда попало во имя самих классов - отсюда
> и косяки с граблями
Правильно! Фтопку классы! Все на асм!
← →
MsGuns © (2009-02-11 16:16) [23]>Ega23 © (11.02.09 16:04) [22]
>Правильно! Фтопку классы! Все на асм!
Ерничать не надо. Но вот зачем там, где нужна просто организация хранения нелинейных данных (вполне умещающихся в рекорды + списки (массивы)), городить классы с горою абсолютно ненужного кода ? Ну если уж не охота морочиться с созданием-уничтожением рекордов, можно использовать коллекции..
← →
Ega23 © (2009-02-11 16:22) [24]
> Но вот зачем там, где нужна просто организация хранения
> нелинейных данных (вполне умещающихся в рекорды + списки
> (массивы)), городить классы с горою абсолютно ненужного
> кода ?
Где ты массу ненужного кода видишь?
И потом, для корректного доступа к этим данным, один фиг придётся тот самый "ненужный" код городить.
← →
MsGuns © (2009-02-11 16:30) [25]>Ega23 © (11.02.09 16:22) [24]
>Где ты массу ненужного кода видишь?
Тебе пальцем ткнуть во все эти пропертя и Get/SetValue или сам посмотришь на свой же "лишний" (к данном случае ессно) код ?
Так это еще пример с двумя полями, а если полей 20, да еще вложенность - я представляю, сколько сотен строчек кода займет у тебя реализация классами :)
← →
Ega23 © (2009-02-11 16:42) [26]
> Тебе пальцем ткнуть во все эти пропертя и Get/SetValue или
> сам посмотришь на свой же "лишний" (к данном случае ессно)
> код ?
Ты вообще внимательно посмотрел на него? [12] и [13] - 2 разных подхода к организации коллекции.
В первом случае всё упрятано в private, а методы доступа, фактически, повторяют методы TObjectList. Но тут ты уже можешь закладывать проверки каких-то значений, соглашаться или не соглашаться добавлять элемент в коллекцию (по каким-то критериям), проверять диапазон индекса и возвращать не Exception а что-то другое и т.п.
Во втором случае - абсолютно тупое наследование TObjectList с переопределённым Items и GetItem, чтобы не нужно было каждый раз приводить TObject к TSomeClassvar
i : Integer;
begin
for i:=0 to List.Count-1 do
if TSomeObject(List.Items[i]).Field1 = что-то then
TSomeObject(List.Items[i]).Field2 := ещё_что-то;
end;
А если в определении property Items[...] в конце ещё директиву default добавить, то вышестоящий код будет выглядетьvar
i : Integer;
begin
for i:=0 to List.Count-1 do
if List[i].Field1 = что-то then
List[i].Field2 := ещё_что-то;
end;
Для разового обращения может быть такой код и несколько избыточен (я про классы).
Но когда это не разовое обращение - то это уже тупо время экономит.
А если такая организация хранилища ещё и общим стилем в рамках проекта является - то тут уже сам Аллах велел.
← →
MsGuns © (2009-02-11 16:49) [27]"Фишка" реализуется простым with и опять-таки нафих классы :)
← →
SingleStranger (2009-02-11 17:26) [28]
> MsGuns © (11.02.09 16:49) [27]
Ну дык, предложи свою реализацию. И мы все подивимся, что, оказывается, можно и так!
← →
sniknik © (2009-02-11 17:44) [29]> Ну дык, предложи свою реализацию.
предлагаю... хотя я не он.
для
> Динамический массив структур (record)
использовать рекордсет (рекордсет даже переводится как "набор рекордов"... а у то что он динамический вне всякого сомнения)
> как свойство класса.
а класс не нужен.
← →
sniknik © (2009-02-11 17:45) [30]а у то ... = ну а то ...
← →
Jeer © (2009-02-11 18:15) [31]Тоже не вижу необходимости лишний раз в классах - просто привычка, видимо, создается.
Вот два варианта работы со списками record
type Tabc = record
A: boolean;
B: integer;
C: string;
end;
type pABC = ^Tabc;
const
N = 10;
var
arABC: array of pABC;
lstABC: TList;
p: pABC;
// Create
lstABC := TList.Create;
SetLength(arABC,N);
for i:= 0 to N-1 do begin
New(p);
lstABC.Add(pABC(p));
arABC[i] := pABC(p);
end;
// Destroy
for i:= 0 to N-1 do begin
if pABC(lstABC[i]) <> nil then
dispose(pABC(lstABC[i]));
end;
SetLength(arABC,0);
lstABC.Free;
// Запись через массив
arABC[0].A := True;
arABC[0].B := 1000;
arABC[0].C := "String";
// Запись через список
p := pABC(lstABC[0]);
p.A := True;
p.B := 1000;
p.C := "String";
// Чтение
ShowMessage(arABC[0].C);
p := pABC(lstABC[0]);
ShowMessage(p.C);
← →
Ega23 © (2009-02-11 18:27) [32]
> Вот два варианта работы со списками record
Ну нормальные варианты. Только я бы всё-таки потомка от TList написал. Дабы dispose каждый раз руками не дёргать.
Но если начать всё это дело обкладывать дурако-защитными вещами - то употеешь.
Т.к. мне никто не помешает сделать так:SetLength(arABC,N);
for i:= 0 to N-1 do begin
New(p);
arABC[i] := pABC(p);
end;
А потомNew(p);
arABC[3] := p;
И аля-улю.
Т.е. мне каждый раз надо прописыватьp1 := arABC[3];
arABC[3] := p;
Dispose(p1);
Если это всё нужно один единственный раз сделать - ну можно. А если 5 раз? А 50?
А так один раз класс написал, что-то типа:
TSerializedItem = class (TObject)
protected
FItemTag : Integer;
procedure ReadStreamData(stream : TStream; bh : TBH); virtual; abstract;
function GetItemSize : Integer; virtual; abstract;
public
constructor Create; virtual;
procedure Assign(Source : TSerializedItem); virtual; abstract;
procedure LoadFromStream(stream : TStream); overload;
procedure LoadFromStream(stream : TStream; const DataSize : Integer); overload;
procedure SaveToStream(stream : TStream); virtual;
end;
TSerializedItemClass = class of TSerializedItem;
TSerializedItemsList = class (TObjectList)
private
function GetItem(Index: Integer): TSerializedItem;
function GetItemSize : Integer;
protected
FItemTag : Integer;
FSelfTag : Integer;
FItemClass : TSerializedItemClass;
public
constructor Create; virtual;
procedure Assign(Source : TSerializedItemsList);
procedure LoadFromStream(stream : TStream); overload;
procedure LoadFromStream(stream : TStream; const DataSize : Integer); overload;
function AddNewItem : TSerializedItem;
procedure SaveToStream(stream : TStream);
property Items[Index : Integer] : TSerializedItem read GetItem; default;
property ListSize : Integer read GetItemSize;
property TagID : Integer read FSelfTag;
end;
TSerializedItemsListClass = class of TSerializedItemsList;
И гоняй его потом, как хочешь, особо не задумываясь.
← →
Sapersky (2009-02-11 18:41) [33]"Фишка" реализуется простым with
Видимо так:
PRec = ^TRec;
TSomeClass = class
private
function GetSRec(Index: Integer): PRec;
public
property SRec[Index: Integer]: PRec read GetSRec;
end;
function TSomeClass.GetSRec(Index: Integer): PRec;
begin
Result := @FSRec[Index];
end;
...
begin
With SomeClass.SRec[i]^ do begin
field1 := 1;
field2 := "bbb";
end;
Хотя из дополнительных возможностей, которые дают Get/Set функции, здесь можно реализовать только контроль индексов.
Jeer © (11.02.09 18:15) [31]
Слава рЕкордам! Сотрём все классы! :)
http://sapersky.narod.ru/files/Arrays.rar
(Arr_AddItem, Arr_DelItem)
← →
Jeer © (2009-02-11 18:41) [34]
> Ну нормальные варианты. Только я бы всё-таки потомка от
> TList написал. Дабы dispose каждый раз руками не дёргать.
>
Да понятно это все - но если плохо понимаешь, что делаешь - известна рекомендация "Займись тем, что у тебя получается"
← →
Jeer © (2009-02-11 18:46) [35]Да я вообще могу вас отправить в Delphi Fundamentals
Там, пожалуй, все дельфинячьи "радости" сосредоточены. :)
В том числе и такого типа.
http://fundementals.sourceforge.net
← →
Джо © (2009-02-11 18:50) [36]
> http://fundementals.sourceforge.net
We"re Sorry but this Project hasn"t yet uploaded their personal webpage yet.
:)
← →
Ega23 © (2009-02-11 18:54) [37]
> Да понятно это все - но если плохо понимаешь, что делаешь
> - известна рекомендация "Займись тем, что у тебя получается"
Возможно у меня это просто на автомате уже получается. Ну не люблю я рекорды. Я ещё могу понять record в случае записи в файл типизированный или там при передаче по сети какой-нибудь. Но в данном конкретном случае (как у автора) я класс бы не задумываясь написал. Тем более, что если понадобится - всегда можно геттеры и сеттеры прикрутить. Лёгким движением руки.
← →
Jeer © (2009-02-11 20:17) [38]
> Джо © (11.02.09 18:50) [36]
We"re Sorry but this Project hasn"t yet uploaded their personal webpage yet.
:)
Да не проблема:
http://sourceforge.net/projects/fundementals/
Давно слежу за развитием проекта David J Butler, еще со времен динозавров.
Не ошибусь, если скажу, что с первыми релизами я ознакомился еще в прошлом веке.
Пользуюсь, не всегда, но пользуюсь.
Отличная подборка классов и утилит по структурам данных, математике, потокам, системным/интернет/xml и прочее.
Просто рекомендую всем, кто не знаком с данной библиотекой - хотя бы для "изучительных" целей.
Того оно стоит.
← →
SingleStranger (2009-02-11 20:32) [39]Давайте я попробую приближенно описАть задачу. Может быть предложите другое решение.
Например есть класс-поток, который постоянно (ПОСТОЯННО) рисует человека. Есть структура описывающая одежду человека;TRec = record
DressCode: integer; // штаны, например. рубашка, шляпа, и т.п.
Color1: TColor;
Color2: TColor;
Color3: TColor;
Style: integer;
end;
Ну, можно еще десяток полей придумать, не важно.
Так вот, у класса рисующего человека есть (должен быть, по задумке) динам. массив этих TRec"ов и на основании него он прорисовывает, перебирая весь массив, одежду. Но массив может быть и пуст, а может быть наполнен 10-20 предметами.
Но при этом, ВСЕГДА есть трусы =) описанные ТОЙ ЖЕ структурой и реализованные как свойств класса, через указатель (примерно так, как предлагал MsGuns (Стволы от Майкрософт, что ли? ;) ) и Sapersky [33]), т.е. они есть всегда. И в общем-то преход к другой структуре возможен, но... Надо будет просто переписать некоторые другие вещи, непосредственно к сабжу не относящиеся.
Вот отсюда и сабж. Как реализовать набор одежды, описанной структурой TRec.
P.S. Не стоит придираться к деталям, это приближенное описание.
← →
Jeer © (2009-02-11 20:39) [40]P.S.
Кста - под НГ вышел, оказывается, новый релиз v 4.
Батлер опять слил все в единый каталог - пральна.
Посмотрел.. по ср. с v.3* - хорошо переработано.
Однако исчезла математике ( вроде как )
Ну и ладно - не ему спорить с современными алгоритмами - у него всегда была простая, не особо эффективная, но работающая реализация:
- векторы, матрицы, компл. числа, рац.числа, статистика, 3D преобразования и пр.
Хотя жаль - довесок неслабый был.
Впрочем, по ссылке, доступны старые версии 3.* - там это должно быть.
Страницы: 1 2 вся ветка
Форум: "Начинающим";
Текущий архив: 2009.04.05;
Скачать: [xml.tar.bz2];
Память: 0.58 MB
Время: 0.008 c