Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2002.10.31;
Скачать: [xml.tar.bz2];

Вниз

Неявное описание типа данных? (Структура для настроек программы)   Найти похожие ветки 

 
lipskiy   (2002-10-20 23:17) [0]

Требуется создать класс, каждый экземпляр которого будет работать только с одним типом данных, но в описании класса (его свойств и методов) тип явно не указывать. То есть конкретный тип данных будет задан при создании экземпляра класса, и до убиения меняться не будет. Все методы и свойства класса таковы, что их работа не зависит от типа данных, но при вызове свойств и методов класса необходимо узнать у него его тип данных.
Предполагается использовать типы: string, integer, real, boolean.
Возможно ли описать такой класс? И как?

Конкретно, что мне нужно, это создать класс для настроек программы, с которым было бы удобно работать. То есть этот класс по сути будет заниматься хранением данных, записью и чтением инишки, вызовом обработчиков изменения настроек, применением настроек по умолчанию и т.п. Также нужно как-то связать каждый параметр с визуальным компонентом на динамической форме настроек.
А может быть есть принципиально иной подход?


 
Оливейра   (2002-10-21 01:14) [1]

А никак. В C++ это делается шаблонами, делфи пока до этого не дорос(ла, ло). Т.е., можно либо создать один класс-предок и от него 4 "перегруженных" потомка, либо извращаться на основе более-менее универсальных встроенных контейнеров типа TList и пр., либо юзать варианты. Одним словом, Delphi для этой задачи не очень удобный инструмент.
Аргумент - родной класс TRegistry для аналогичных целей использует ряд соответствующих функций - readInteger, readString и т.п.


 
lipskiy   (2002-10-21 01:22) [2]

Ясно, я так и думал...
Придется писать четыре класса, видимо это проще и правильнее будет в данном случае.


 
PVOzerski   (2002-10-21 03:41) [3]

Ну, вот что... Касательно шаблонов: во-первых, это игры с С++-ным препроцессором (развитие макроподстановок), IMHO, к этапу Run-time отношения не имеюшие (здесь, впрочем, я могу и ошибаться), во-вторых, с некоторыми извратами и вопреки воле разработчиков Object Pascal, они реализуемы в Delphi игрой с include-файлами (подробнее - ищи материал на Королевстве), в четвертых - с properties номер не пройдет, но с нетипизированными аргументами в некоторых случаях кое-что выйдет
(array of const, например, решит проблему распознания типа, а дальше - забота программиста) - не говоря уже о variant. IMHO, сила шаблонов - в их сочетаемости с перегружаемыми (в том числе и в RTL) операторами и функциями, а в остальных случаях без них обойтись вполне можно.


 
Rouse_   (2002-10-21 03:55) [4]

А вот у меня есть еще предложение, (сильно ногами не бейте только) создать процедуру которая будет сама конвертировать входные данные в формат с которым работает класс (если это конечно возможно по условию)

Желаю успехов


 
Александр С.   (2002-10-21 07:51) [5]

Господа!
А указатели и overload функции/процедуры разве не позволят сделать то, что требуется.


 
Anatoly Podgorestky   (2002-10-21 07:59) [6]

Может Variant


 
Opuhshii   (2002-10-21 08:51) [7]

2Александр С. © (21.10.02 07:51)
"Требуется создать класс, каждый экземпляр которого будет работать..." не 4 и не 5 классов.... ;)

Variant... либо указатели и память выделять от типа данных,..


 
NailS   (2002-10-21 09:21) [8]


> lipskiy © (20.10.02 23:17)


> создать класс для настроек программы, с которым было бы
> удобно работать

Как вариант, для хранения настроек можно создать класс, который умеет сохранять параметры куда-то и читать параметры откуда-то. В качестве самих параметров использовать published properties класса. Их список и тип данных можно получить динамически (GetPropList).

Таким образом в дальнейшем создание класса, содержащего необходимые тебе параметры будет выглядеть как наследование от базового класса, добавление необходимых свойств и указание пути откуда читать параметры. Все.


 
REA   (2002-10-21 11:03) [9]

Можно Variant - в нем и тип есть. Придется правда проверки на тип делать всегда.


 
Ydna   (2002-10-21 11:52) [10]

type
TMyTypes=(mtString,mtBoolean, mtInteger, mtReal);

TDataRecord=record case AType:TMyTypes of
mtString: (strValue :PString);
mtBoolean:(boolValue:boolean);
mtInteger:(intValue :integer);
mtReal: (realValue:real);
end;

TMyClass=class
private
data:TDataRecord;
//...
end;

В TDataRecord.AType - тип, прочие значения лежат по одному адресу.
Единственное, строки придется хранить как указатели.


 
алгоритм Бойера - Мура,   (2002-10-21 13:03) [11]

Я когда-то писал нечто подобное.
В упрощённом виде это выглядело примерно так:


TGfgItem = class
private
FName: string;
FData: Pointer;
FTypeID: TTypeID;
// FIsProp: Boolean;
protected
function GetValue: string; virtual;
procedure SetValue(const AValue: string); virtual;
public
property Value: string read GetValue write SetValue;
property Name: string read FName;

constructor Create(const AName: string; var AData: Integer); overload;
constructor Create(const AName: string; var AData: string); overload;
constructor Create(const AName: string; var AData: Boolean); overload;
constructor Create(const AName: string; var AData: Double); overload;
// constructor CreateProp(const AName, APropName: string; AInstance: TObject);
end;

constructor TGfgItem.Create(const AName: string; var AData: string);
begin
FName := AName;
FData := @AData;
FTypeID := tpString;
end;

constructor TGfgItem.Create(const AName: string; var AData: Integer);
begin
FName := AName;
FData := @AData;
FTypeID := tpInteger;
end;

constructor TGfgItem.Create(const AName: string; var AData: Double);
begin
FName := AName;
FData := @AData;
FTypeID := tpReal;
end;

constructor TGfgItem.Create(const AName: string; var AData: Boolean);
begin
FName := AName;
FData := @AData;
FTypeID := tpBoolean;
end;

function TGfgItem.GetValue: string;
begin
case FTypeID of
tpInteger: Result := IntToStr(Integer(FData^));
tpString: Result := AnsiString(FData^);
tpBoolean: if Boolean(FData^) then Result := "True" else Result := "False"; //On/Off
tpReal: Result := Format("%5.3g", [Double(FData^)]);
end;
end;

procedure TGfgItem.SetValue(const AValue: string);
begin
case FTypeID of
tpInteger: Integer(FData^) := StrToInt(AValue);
tpString: AnsiString(FData^) := AValue;
tpBoolean: Boolean(FData^) := CompareText(AValue, "True") = 1;
tpReal: Double(FData^) := StrToFloat(AValue);
end;
end;




 
reonid   (2002-10-21 13:04) [12]

Прошу прощения, ник не поменял.


 
REA   (2002-10-21 13:11) [13]

Ну в принципе Variant и получился, только хуже


 
reonid   (2002-10-21 13:41) [14]

2REA ©
Тут несколько иной принцип. Это не вариант как значение,
а нечто вроде вариантной ссылки со строковым интерфейсом.

Я их использовал примерно так:

CgfFile.Add(TCfgItem.CreateProp("MainFormWidth", "Width", MainForm));
CgfFile.Add(TCfgItem.Create("Count", cnt));
...

CfgFile.Load;
// В Form1.Width и переменную cnt загрузились значения из файла
//

CfgFile.Store;
// В файл сохранились значения MainForm.Width и cnt
//

Или:

function TDlgForm.Execute: Boolean;
begin
Edit1.Text := item.Value;
Result := ShowModal = mrOk;
if Result then item.Value := Edit1.Text;
end;


 
Ydna   (2002-10-21 13:45) [15]

Угу. A как быть в случае:
var
Item:TGfgItem;

procedure foo;
var
s:string;
begin
s:="BUG!";
Item:=TGfgItem.Create(s,s);
end;

begin
foo;
ShowMessage(Item.Value); // И тут кылдык, поскольку FData ссылается в никуда
end;



 
reonid   (2002-10-21 13:46) [16]

2REA ©
И, если уж на то пошло, это было написано на трубопаскале под ДОС, когда никаких вариантов ещё не было и в помине.


 
reonid   (2002-10-21 13:53) [17]

2Ydna ©
Именно так, и никак иначе.
На самом деле было ещё хуже:

var
w: Word;

procedure foo;
begin
Item:=TGfgItem.Create("I: Integer", W); // Ёёёё
end;

Ну не совсем безопасный приём программирования, соглашусь.
А кому сейчас легко?


 
Ydna   (2002-10-21 14:00) [18]

2reonid ©
А копировать значение, вместо передачи указателя никак? ;-)
Для строк, например, есть NewStr и DisposeStr, хоть и не рекомендуются Борландом, но работают:

constructor TGfgItem.Create(const AName, AData: string);
begin
FName := AName;
FData :=NewStr(AData);
FTypeID := tpString;
end;

destructor Destroy;
begin
if FTypeID = tpString then DisposeStr(FData);
inherited;
end;

а для всего прочего хранить в UNION (см. 21.10.02 11:52)


 
reonid   (2002-10-21 14:28) [19]

2Ydna ©
Так копировать можно и с Вариантами.
Тут сама суть в том, что TCfgItem является неким посредником для реально существующей переменной/свойства и позволяет через строковый интерфейс их (реальные переменные) читать и менять.


 
Ydna   (2002-10-21 14:39) [20]

2reonid ©
Не очень понятно только какую выгоду (кроме веселой отладки и возможности работать с некоторыми типами как со строками) можно получить от такого посредника...

Я писал компоненту для хранения настроек и делал там так:
1) Все сохраняемые значения описываются классом-наследником TCollectionItem (чтобы описывать их в дизайнере).
2) Значение в памяти хранится либо как строка, либо, если элемент коллекции связан со свойством некоторого компонента - то в этом свойстве компонента и храниться (вот тут ссылка).

Хранить значения как строки не больно - в инишнике все равно все строками будет, а с памятью сейчас проблем не бывает ;-)


 
reonid   (2002-10-21 14:59) [21]

2Ydna ©
Ну видишь, в случае свойств ты всё же пользуешься ссылками
(ну некоторым их подобием).

Ну а у меня хранятся ссылки не только на св-ва,
но и на переменные (или поля объектов), чтобы реально всё
информация хранилась там, где ей положено - не из-за памяти,
а чтобы избежать дублирования.

Обычно объект предоставлял программе свою конфигурационную секцию, через которую можно было сохранять и загружать состояние объекта.


 
lipskiy   (2002-10-22 00:24) [22]


> Ydna © (21.10.02 11:52)

Че-т я не очень понял, как потом обращаться к элементу записи - ведь придется явно указывать поле, а значит - и тип?


> reonid © (21.10.02 13:03)

Че-т я не очень понял, как получить параметр не в виде строки, а в виде его типа данных?

Честно говоря, оба варианта мне нравятся, так как находятся на грани моего понимания :) Но как-же все-таки лучше-то?

Ребята, если не затруднит, нельзя ли конкретный примерчик для двух типов данных - string и integer:
- описание класса для одного параметра;
- пример создания списка параметров - списка экзепляров;
- записать новое значение string или integer;
- прочитать значение string или integer;
Я просто не могу пока охватить идею целиком, пример бы очень помог (можно просто с лету написать, я разберусь).



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2002.10.31;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.52 MB
Время: 0.008 c
1-101378
jen_bond
2002-10-21 13:06
2002.10.31
Защита софта


14-101518
Johnny Smith
2002-10-10 11:53
2002.10.31
Кстати, а как там наш одиночка-самоубийца с видеокамарой?


3-101116
Vagrant
2002-10-10 04:45
2002.10.31
FIBDataSet and BLOB


6-101409
Kolesya
2002-08-29 20:16
2002.10.31
Помогите с отключением DIALUP


8-101386
Maxuz
2002-07-07 14:19
2002.10.31
TImage и фликеры :-(





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский