Класс-обёртка для integer (например)...

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Класс-обёртка для integer (например)...

Сообщение leo_bsv » 11.01.2012 02:07:00

К примеру определён такой класс
Код: Выделить всё
type
  TPositiveInteger = class
  private
    FValue: integer;
    procedure SetValue(AValue:integer);
  public
    property Value: integer read FValue write SetValue;
  end;                               

можно ли свойство Value сделать таким "умолчательным" что значение данного свойства выводилось бы сразу при обращении к объекту этого класса, т.е. чтобы не лезть в свойство за значением...
т.е. с описанным классом получится так
Код: Выделить всё
var x:TPositiveInteger;
...
x.Value:=...

а хочется вот так :!:
Код: Выделить всё
var x:TPositiveInteger;
...
x:=...

знаю - я сосем обнаглел :wink: но вдруг есть в жизни счастье :?:
Аватара пользователя
leo_bsv
постоялец
 
Сообщения: 276
Зарегистрирован: 04.08.2010 16:26:10
Откуда: Йошкар-Ола

Re: Класс-обёртка для integer (например)...

Сообщение Brainenjii » 11.01.2012 07:08:19

Можно нескромный вопрос - а зачем это? Мне часто нужно было Integer как объект для работы со списком чисел. Потом появились Generic'и, а потом я узнал, что можно работать и с обычным TList'ом:
Код: Выделить всё
..
  TIntegerList = Specialize TFPGList<Integer>;
..
Var
  aList: TList;
  aIntegerList: TIntegerList;
Begin
  aList := TList.Create;
  aIntegerList := TIntegerList.Create;
  For i := 0 To 10 Do
    Begin
      aList.Add(TObject(i * 2));
      aIntegerList.Add(i * 2);
    End;
  For i := 0 To 10 Do
    WriteLn(Integer(aList[i]), aIntegerList[i]);
End;
..
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Re: Класс-обёртка для integer (например)...

Сообщение AlexVinS » 11.01.2012 09:09:05

Можно переопределить оператор присваивания.

Код: Выделить всё
operator := (r: Integer) res: TPositiveInteger;
begin
res := TPositiveInteger.Create;
res.Value := r;
end;

operator := (r: TPositiveInteger) res: Integer;
begin
res := r.Value ;

end;



Главное на мой взгляд избегать утечек памяти при таком подходе. А вобщем должно работать.
Аватара пользователя
AlexVinS
новенький
 
Сообщения: 95
Зарегистрирован: 27.01.2009 01:18:01

Re: Класс-обёртка для integer (например)...

Сообщение leo_bsv » 11.01.2012 17:18:22

Brainenjii писал(а):Можно нескромный вопрос - а зачем это?

это затем что хочется контролировать вводимое значение, т.е. TPositiveInteger - это значение > 0,
а например сделать класс TNonNegativeInteger - значение 0 и более...
соответственно TNegativeInteger - значение < 0...
далее есть объявление классов...
Код: Выделить всё
type
  TPositiveInteger = class
  private
    FValue: integer;
    procedure SetValue(AValue:integer);
  public
    property Value: integer read FValue write SetValue;
  end;                 
...
  TNonNegativeInteger = class             
...
  TNegativeInteger = class             

в методах которых описана функция SetValue, которая и контролирует вводимые значения,
затем описываем любой класс
Код: Выделить всё
type
  TVasiaPupkinClass = class
  private
    FPositiveField: TPositiveInteger;
    FNonNegativeField: TNonNegativeInteger;
    FNegativeField: TNegativeInteger;
  public
    PositiveField: TPositiveInteger read FPositiveField write FPositiveField;
    NonNegativeField: TNonNegativeInteger read FNonNegativeField write FNonNegativeField;
    NegativeField: TNegativeInteger read FNegativeField write FNegativeField;
  end;

Т.е. в классе TVasiaPupkinClass просто происходит присвоение значения полю, а ввод контролирует процедура SetValue класса TPositiveInteger, TNonNegativeInteger, TNegativeInteger по задумке автора это должно сократить объём кода :P
Прямое же присвоение значения нужно для удобопользования... классы TPositiveInteger, TNonNegativeInteger, TNegativeInteger простые - свойство то одно всего...

Добавлено спустя 5 часов 8 минут 52 секунды:
AlexVinS писал(а):Можно переопределить оператор присваивания.

чуть выше в этом же посте описано что таких классов несколько - можно для каждого переопределить?
в теле переопределения оператора присваивания должно содержаться условие с проверкой отсекающей ненужные значения и выдающее исключение... такой подход вообще практикуют :?:
Аватара пользователя
leo_bsv
постоялец
 
Сообщения: 276
Зарегистрирован: 04.08.2010 16:26:10
Откуда: Йошкар-Ола

Re: Класс-обёртка для integer (например)...

Сообщение MageSlayer » 11.01.2012 23:38:04

... по задумке автора это должно сократить объём кода...


ООП уменьшает размер кода.
Супер. Посмеялся, спасибо.

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

И вообще, как там говорили классики - "Лучше иметь сто функций работающих с одним типом данных, чем 10 функций, работающих с 10 типами данных".
Вы же, похоже, делаете все в точности наоборот.
MageSlayer
постоялец
 
Сообщения: 216
Зарегистрирован: 07.09.2006 12:30:44

Re: Класс-обёртка для integer (например)...

Сообщение alexs » 12.01.2012 00:41:29

leo_bsv писал(а):это затем что хочется контролировать вводимое значение, т.е. TPositiveInteger - это значение > 0,
а например сделать класс TNonNegativeInteger - значение 0 и более...
соответственно TNegativeInteger - значение < 0...


А если просто объявить перечисляемый тип?
Код: Выделить всё
type
  TNegativeInteger = - (MaxInt - 1) .. -1;
  TNonNegativeInteger = 0 ..  MaxInt;
  TPositiveInteger = 1 ..MaxInt;
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4064
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Re: Класс-обёртка для integer (например)...

Сообщение leo_bsv » 12.01.2012 01:19:21

alexs писал(а):А если просто объявить перечисляемый тип?

Да, то что надо. Спасибо за дельный совет.
С integer всё понятно, а вот с double как быть? думаю приемлемо будет переопределить оператор присваивания и контролировать диапазон в нём :?:
MageSlayer писал(а):Вы же, похоже, делаете все в точности наоборот.

Отойди, ты заслоняешь мне солнце...
Аватара пользователя
leo_bsv
постоялец
 
Сообщения: 276
Зарегистрирован: 04.08.2010 16:26:10
Откуда: Йошкар-Ола

Re: Класс-обёртка для integer (например)...

Сообщение AlexVinS » 12.01.2012 05:46:40

alexs писал(а):...

А если просто объявить перечисляемый тип?
Код: Выделить всё
type
  TNegativeInteger = - (MaxInt - 1) .. -1;
  TNonNegativeInteger = 0 ..  MaxInt;
  TPositiveInteger = 1 ..MaxInt;


То для проверки вводимых значений придется включать range checks (потребует определенных усилий чтобы включить только там где надо, а еще большой вопрос КАК вводятся значения. Компилятор проверит ТОЛЬКО константы) или всеравно проверять вручную. Нет, пока решения лучше класса-обертка не представлено.

Добавлено спустя 11 минут 21 секунду:
leo_bsv писал(а):чуть выше в этом же посте описано что таких классов несколько - можно для каждого переопределить?
в теле переопределения оператора присваивания должно содержаться условие с проверкой отсекающей ненужные значения и выдающее исключение... такой подход вообще практикуют :?:


1. Можно переопределять для каждого класса. (причем для констант удобно использовать подтипы - subrange types - которые выше почему-то названы перечислимыми. И для их оператор присваивания тоже можно переопределить, причем можно и в обход проверки).

2. Проверка правильности должна быть в одном месте например в SetValue или вообще отдельный метод (зависит от конкретной задачи).
Аватара пользователя
AlexVinS
новенький
 
Сообщения: 95
Зарегистрирован: 27.01.2009 01:18:01

Re: Класс-обёртка для integer (например)...

Сообщение alexs » 12.01.2012 19:34:03

AlexVinS писал(а):То для проверки вводимых значений придется включать range checks (потребует определенных усилий чтобы включить только там где надо, а еще большой вопрос КАК вводятся значения. Компилятор проверит ТОЛЬКО константы) или всеравно проверять вручную. Нет, пока решения лучше класса-обертка не представлено.

Допустимость данных надо проверять при их появлении.
Проверка при каждом чихе - не есть хорошо.
Пусть ваш интерфейс ввода обеспечит появление корректных данных.
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4064
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Re: Класс-обёртка для integer (например)...

Сообщение leo_bsv » 12.01.2012 21:18:26

alexs писал(а):Пусть ваш интерфейс ввода обеспечит появление корректных данных.

хм... похоже вернулись к тому с чего начали - проверять ввод в функции SetValue...
вопрос вообще-то был - как упростить присвоение, опустив в операторе соответствующий метод... в принципе ответ получен - с помощью переопределения оператора.
Аватара пользователя
leo_bsv
постоялец
 
Сообщения: 276
Зарегистрирован: 04.08.2010 16:26:10
Откуда: Йошкар-Ола

Re: Класс-обёртка для integer (например)...

Сообщение alexs » 12.01.2012 21:38:41

leo_bsv писал(а):хм... похоже вернулись к тому с чего начали - проверять ввод в функции SetValue...

Нет
Именно для таких случае используем свой тип с ограничем на данные - это уменьшает вероятность появления ошибок внутри системы.
А вот на уровне взаимодействия системы с внешним видом ставим проверки на коректность данных. Для этих проверок - делать специальный класс - избыточно. Достаточно обычного процедурного подхода.

По моему мнению - надо соблюдать баланс. Т.е. до определённого уровня сложности обрабатываемого объекта - достаточно использовать процедурный подход.
Но всегда есть грань, начиная с которой для формализации действий уже лучше использовть объектный подход на все 200%.
Просто ваша проблема с контролем данных - это чисто процедурная задача, причём очень низкого уровня.
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4064
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Re: Класс-обёртка для integer (например)...

Сообщение leo_bsv » 13.01.2012 22:36:11

alexs писал(а):Проверка при каждом чихе - не есть хорошо.
Пусть ваш интерфейс ввода обеспечит появление корректных данных.

у меня не интерфейс - это всё мне нужно для ODFProc...
есть готовый файл - хмл кстати из .odt, а эти странные типы обозначены в спецификации OASIS Open Docment Format...
поэтому влиять на чтение из файла нет смысла, можно читать и в integer... а вот проверку при записи производить нужно... т.к. все эти типы имеют логическую основу.
можно конечно для каждого поля описываемого класса прописывать Set_ процедуру и в ней осуществлять нужную проверку, но это не удобно - удобнее сразу описать поле определенным типом и в нем контролировать ввод, но тут натыкаюсь на атрибут, или переопределять оператор присваивания чтоб атрибут не вводить при дальнейшем использовании модуля, или через Set_ для каждого свойства и обойтись без этих типов... с типами конечно и код гораздо прозрачней, но переопределять оператор присваивания... хз... буду экспериментировать.

Добавлено спустя 36 минут 43 секунды:
AlexVinS писал(а):Главное на мой взгляд избегать утечек памяти при таком подходе. А вобщем должно работать.

как отследить есть утечка или нет?
если в качестве типа свойства используется собственный класс, то при уничтожении класса-владельца данного свойства объект находящийся в этом свойстве может уничтожаться автоматически или его нужно всегда освобождать в деструкторе класса? как отследить все объекты типа TPositiveInteger?
alexs писал(а):Проверка при каждом чихе - не есть хорошо.

в моём случае - это так же страшно как функция Set... прикрепляемая к любому полю создаваемого класса...

Добавлено спустя 47 минут 18 секунд:
Free Pascal : Reference guide. писал(а):The difference between objects and classes is mainly that an object is allocated on the stack, as an ordinary record would be, and that classes are always allocated on the heap. In the following example:
Var
A : TSomeObject; // an Object
B : TSomeClass; // a Class

The main difference is that the variable A will take up as much space on the stack as the size of the object (TSomeObject). The variable B, on the other hand, will always take just the size of a pointer on the stack. The actual class data is on the heap.

From this, a second difference follows: a class must always be initialized through its constructor, whereas for an object, this is not necessary. Calling the constructor allocates the necessary memory on the heap for the class instance data.

Может быть описать эти типы не как классы а как объекты :?:
Аватара пользователя
leo_bsv
постоялец
 
Сообщения: 276
Зарегистрирован: 04.08.2010 16:26:10
Откуда: Йошкар-Ола

Re: Класс-обёртка для integer (например)...

Сообщение Odyssey » 14.01.2012 13:53:44

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

Имхо №1: удобство внутри библиотеки -- вещь вторичная по сравнению с удобством её использования. Поэтому вариант, когда пользователь должен у каждого свойства вызывать SetValue, я бы отбросил. Лучше вынести проверку в отдельную процедуру и нагенерировать сеттеров (SetXXX) с вызовом этой процедуры. Автоматически генерировать сеттеры может и Lazarus, останется только вставить в них вызов процедуры проверки.
Имхо №2: перегрузку операторов в коде на Object Pascal без крайней на то необходимости лучше не делать.
leo_bsv писал(а):если в качестве типа свойства используется собственный класс, то при уничтожении класса-владельца данного свойства объект находящийся в этом свойстве может уничтожаться автоматически или его нужно всегда освобождать в деструкторе класса?

Нужно всегда освобождать в деструкторе.
Odyssey
энтузиаст
 
Сообщения: 580
Зарегистрирован: 29.11.2007 17:32:24

Re: Класс-обёртка для integer (например)...

Сообщение iskander » 14.01.2012 14:49:08

leo_bsv писал(а):как отследить есть утечка или нет?

модуль heaptrc?
iskander
энтузиаст
 
Сообщения: 623
Зарегистрирован: 08.01.2012 18:43:34

Re: Класс-обёртка для integer (например)...

Сообщение leo_bsv » 14.01.2012 20:20:34

Odyssey писал(а):Лучше вынести проверку в отдельную процедуру и нагенерировать сеттеров (SetXXX) с вызовом этой процедуры. Автоматически генерировать сеттеры может и Lazarus, останется только вставить в них вызов процедуры проверки.

ну примерно это и делаю... код конечно получается переполнен кучей двухстрочных процедур...
Код: Выделить всё
...
    procedure SetNumberColumnsRepeated(AValue: integer);
    procedure SetNumberColumnsSpanned(AValue: integer);
    procedure SetNumberMatrixColumnsSpanned(AValue: integer);
    procedure SetNumberMatrixRowsSpanned(AValue: integer);
    procedure SetNumberRowsSpanned(AValue: integer);
...
// процедура проверки условия...
procedure SetPosiviteInteger(var F: integer; const AValue:integer);
begin
  if AValue<=0 then
    raise EInOutError.Create('Value mast be > 0.')
  else F:=AValue;
end;

{Процедуры SetXXXX}

procedure TOdtTableCell.SetNumberColumnsRepeated(AValue: integer);
begin
  if FNumberColumnsRepeated=AValue then Exit;
  SetPosiviteInteger(FNumberColumnsRepeated,AValue);
end;

procedure TOdtTableCell.SetNumberColumnsSpanned(AValue: integer);
begin
  if FNumberColumnsSpanned=AValue then Exit;
  SetPosiviteInteger(FNumberColumnsSpanned,AValue);
end;

procedure TOdtTableCell.SetNumberMatrixColumnsSpanned(AValue: integer
  );
begin
  if FNumberMatrixColumnsSpanned=AValue then Exit;
  SetPosiviteInteger(FNumberMatrixColumnsSpanned,AValue);
end;

procedure TOdtTableCell.SetNumberMatrixRowsSpanned(AValue: integer);
begin
  if FNumberMatrixRowsSpanned=AValue then Exit;
  SetPosiviteInteger(FNumberMatrixRowsSpanned,AValue);
end;

procedure TOdtTableCell.SetNumberRowsSpanned(AValue: integer);
begin
  if FNumberRowsSpanned=AValue then Exit;
  SetPosiviteInteger(FNumberRowsSpanned,AValue);
end;

Минус такого подхода - не видно какой тип у каждого поля... т.е. для пишущего и в дальнейшем использующего модуль человека не ясен будет принцип разбора вводимого значения (нужно будет рыться в коде чтобы понять)... а если объявить поля соответствующим типом, например TPositiveInteger, то из названия понятно с чем имеешь дело.
Аватара пользователя
leo_bsv
постоялец
 
Сообщения: 276
Зарегистрирован: 04.08.2010 16:26:10
Откуда: Йошкар-Ола

След.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex [Bot] и гости: 237

Рейтинг@Mail.ru