| Предыдущая версия справа и слева
Предыдущая версия
Следующая версия
|
Предыдущая версия
|
bb:redbook:208 [2018/11/30 01:13] 127.0.0.1 внешнее изменение |
bb:redbook:208 [2020/10/29 07:08] (текущий) |
| Итак, свойства объекта, в первом приближении — это поля записи. Поля могут быть как базовых типов (INTEGER, REAL и т. д.), так и пользовательские типы(например, tString, tPerson и т. д.). Пример того, как это может выглядеть представлен ниже: | Итак, свойства объекта, в первом приближении — это поля записи. Поля могут быть как базовых типов (INTEGER, REAL и т. д.), так и пользовательские типы(например, tString, tPerson и т. д.). Пример того, как это может выглядеть представлен ниже: |
| | |
| | TYPE |
| | tPerson = RECORD (* объект человек *) |
| | name: ARRAY 128 OF CHAR; (* имя *) |
| | family: ARRAY 128 OF CHAR; (* фамилия *) |
| | age: SHORTINT; (* возраст *) |
| | id: INTEGER; (* уникальный идентификатор *) |
| | subset: INTEGER; (* счёт в банке *) |
| | count: REAL (* сколько денег на счёте *) |
| | END; |
| В пользовательском типе tPerson использованы массив литер, короткое целое и два целых. В комментариях, на всякий случай приводятся описания полей. Часто бывает удобней, чем смотреть в документацию (хотя, в ББ — это как раз не проблема). | В пользовательском типе tPerson использованы массив литер, короткое целое и два целых. В комментариях, на всякий случай приводятся описания полей. Часто бывает удобней, чем смотреть в документацию (хотя, в ББ — это как раз не проблема). |
| |
| |
| Внутри модуля в КП, любая струтктура доступна, как на чтение, так и на запись. Давайте попробуем для начала осторожно разрешить отдельные поля на чтение для внешнего модуля. Например, идентификатор пользователя банковской системы должен быть известен в любом случае. Также при выходе замуж женщины с удовольствием меняют фамилии, а приёмные дети также меняют и отчество. В редких случаях, люди даже могут поменять имя. Код разрещающий чтение части данных представлен ниже: | Внутри модуля в КП, любая струтктура доступна, как на чтение, так и на запись. Давайте попробуем для начала осторожно разрешить отдельные поля на чтение для внешнего модуля. Например, идентификатор пользователя банковской системы должен быть известен в любом случае. Также при выходе замуж женщины с удовольствием меняют фамилии, а приёмные дети также меняют и отчество. В редких случаях, люди даже могут поменять имя. Код разрещающий чтение части данных представлен ниже: |
| | TYPE |
| | tPerson* = RECORD (* объект человек *) |
| | name-: ARRAY 128 OF CHAR; (* имя *) |
| | family-: ARRAY 128 OF CHAR; (* фамилия *) |
| | age: SHORTINT; (* возраст *) |
| | id-: INTEGER; (* уникальный идентификатор *) |
| | subset-: INTEGER; (* счёт в банке *) |
| | count: REAL (* сколько денег на счёте *) |
| | END; |
| | |
| В этом коде, внешний модуль уже может узнать, а есть ли вообще такой клиент у банка, а также номер его счёта (а как ещё деньги можно зачислить?). Как видно из кода, появились дополнительные символы у полей ("-"). Символ "*" означает, что объект при компиляции будет экспортирован (ссылка на объект будет доступна для внешних модулей). Символ "-" означает, что ссылка на объект будет доступна внешним модулям, значение объекта можно считать, но нельзя изменить. Вот так просто. | В этом коде, внешний модуль уже может узнать, а есть ли вообще такой клиент у банка, а также номер его счёта (а как ещё деньги можно зачислить?). Как видно из кода, появились дополнительные символы у полей ("-"). Символ "*" означает, что объект при компиляции будет экспортирован (ссылка на объект будет доступна для внешних модулей). Символ "-" означает, что ссылка на объект будет доступна внешним модулям, значение объекта можно считать, но нельзя изменить. Вот так просто. |
| ==== 3. Методы объекта ==== | ==== 3. Методы объекта ==== |
| Как уже было упомянуто, метод — это процедуры привязанная к данным. Т. е. процедура требует данные определённого типа. И при этом, поскольку такая процедура привязана, она может быть вызвана с нотацией через точку ("."), что частично облегчает понимание текста программы. Давайте положим что-нибудь на счёт: | Как уже было упомянуто, метод — это процедуры привязанная к данным. Т. е. процедура требует данные определённого типа. И при этом, поскольку такая процедура привязана, она может быть вызвана с нотацией через точку ("."), что частично облегчает понимание текста программы. Давайте положим что-нибудь на счёт: |
| | PROCEDURE (VAR p: tPerson) Accum* (m: REAL), NEW; |
| | BEGIN |
| | p.count := p.count + m; |
| | Log.Real(p.count); Log.Ln |
| | END Accum; |
| Этот метод (процедура специального вида) принимает параметр (VAR self: tPerson) в качестве скрытой ссылки. В последствие, вызов person.Accum(n) будет выглядеть именно так, где person — есть объект типа tPerson. После имени метода Accum* (который между прочим экспортирован) имеет в качестве аргумента некоторое число денег m. Эта сумма прибавляется к тому, что уже хранится на счёте, после чего новая сумма выводится на экран. Если эта операция выполняется вручную, убедиться, что зачисление прошло — лишним не будет. Ключевое слово VAR имеет в объявлении функции специальный смысл, пока не рассматриваем (существует и другой способ привязки процедуры к типу). Ключевое слово NEW в данном случае, говорит о том, что у объекта tPerson появился новый метод, который ранее не существовал. | Этот метод (процедура специального вида) принимает параметр (VAR self: tPerson) в качестве скрытой ссылки. В последствие, вызов person.Accum(n) будет выглядеть именно так, где person — есть объект типа tPerson. После имени метода Accum* (который между прочим экспортирован) имеет в качестве аргумента некоторое число денег m. Эта сумма прибавляется к тому, что уже хранится на счёте, после чего новая сумма выводится на экран. Если эта операция выполняется вручную, убедиться, что зачисление прошло — лишним не будет. Ключевое слово VAR имеет в объявлении функции специальный смысл, пока не рассматриваем (существует и другой способ привязки процедуры к типу). Ключевое слово NEW в данном случае, говорит о том, что у объекта tPerson появился новый метод, который ранее не существовал. |
| |
| C начислением всё в порядке. Давайте теперь немного денег потратим: | C начислением всё в порядке. Давайте теперь немного денег потратим: |
| | PROCEDURE (VAR p: tPerson) Debet* (m: REAL), NEW; |
| | BEGIN |
| | p.count := p.count - m; |
| | Log.Real(p.count); Log.Ln |
| | END Debet; |
| По аналогии с предыдущим методом здесь происходит получение скрытой ссылки на объект типа tPerson и вычитание указанной суммы со счёта. В обоих методах скрывается существенная ошибка, которая демонстрируется выполнением следующего кода: | По аналогии с предыдущим методом здесь происходит получение скрытой ссылки на объект типа tPerson и вычитание указанной суммы со счёта. В обоих методах скрывается существенная ошибка, которая демонстрируется выполнением следующего кода: |
| | PROCEDURE Start*; |
| | BEGIN |
| | anonim.Accum(50); |
| | anonim.Debet(60) |
| | END Start; |
| | |
| | компилируется "TestPerson" |
| | Start теперь в символьном файле 208 532 |
| | старый модуль TestPerson выгружен |
| | 50.0 |
| | -10.0 |
| Списано денег больше, чем есть на счёте. Пополнение счёта также может привести к ошибке (если объект anonim является невероятно богатым человеком; это всё из-за типа REAL). В тоже время, можно зачислить отрицательную сумму. Что в обычной практике — не допускается. | Списано денег больше, чем есть на счёте. Пополнение счёта также может привести к ошибке (если объект anonim является невероятно богатым человеком; это всё из-за типа REAL). В тоже время, можно зачислить отрицательную сумму. Что в обычной практике — не допускается. |
| |
| Полный текст программы представлен ниже: | Полный текст программы представлен ниже: |
| | MODULE TestPerson; |
| | (* модуль описывает объект банковского учёта *) |
| | |
| | IMPORT Log; |
| | |
| | TYPE |
| | tPerson = RECORD (* объект человек *) |
| | name-: ARRAY 128 OF CHAR; (* имя *) |
| | family-: ARRAY 128 OF CHAR; (* фамилия *) |
| | age: SHORTINT; (* возраст *) |
| | id-: INTEGER; (* уникальный идентификатор *) |
| | subset-: INTEGER; (* счёт в банке *) |
| | count: REAL (* сколько денег на счёте *) |
| | END; |
| | |
| | VAR |
| | anonim*: tPerson; |
| | |
| | PROCEDURE (VAR p: tPerson) Accum* (m: REAL), NEW; |
| | BEGIN |
| | p.count := p.count + m; |
| | Log.Real(p.count); Log.Ln |
| | END Accum; |
| | |
| | PROCEDURE (VAR p: tPerson) Debet* (m: REAL), NEW; |
| | BEGIN |
| | p.count := p.count - m; |
| | Log.Real(p.count); Log.Ln |
| | END Debet; |
| | |
| | PROCEDURE Start*; |
| | BEGIN |
| | anonim.Accum(50); |
| | anonim.Debet(60) |
| | END Start; |
| | |
| | BEGIN |
| | END TestPerson. |
| | |
| | (!)TestPerson.Start |
| В приведённом коде всё ещё сохраняется ошибка со списанием денег. Решить эту проблему предлагается самостоятельно в качестве задания. | В приведённом коде всё ещё сохраняется ошибка со списанием денег. Решить эту проблему предлагается самостоятельно в качестве задания. |
| [↑] | [↑] |