Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






О семантике передачи параметров значением и возвращении значения функцией.






Семантика передачи параметров значением фактически базируется на семантике присваивания, именно так она и была определена в свое время в теме «Процедуры и функции». Естественно это повлечет свои последствия для случая, когда параметр имеет динамический тип. Аналогичная ситуация с семантикой возвращения значения функцией.

Объекты. Семантика присваивания и последствия этого.

Ø Object Pascal 2.

Для объектов действует семантика присваивания по ссылке, естественно последствия проявляются в зависящих от неё местах.

¨ Присваивание переменной типа класс значения переменной типа класс даёт эффект двух имен у одного хранилища данных.

Если в левой части присваивания находится ранее уже созданный объект, то возможно получим «мусор» – хранилище данных потеряет обозначение (одно из ранее имевшихся).

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

¨ Если параметр функции-процедуры передается значением, а в качестве фактического параметра в вызове используется объект, то реально получим эффект передачи параметра ссылкой.

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

¨ Возвращаемое функцией значение всегда сохраняется во временном хранилище данных, откуда оно и возвращается. Поэтому никаких неожиданных эффектов от семантики по ссылке не проявляется.

Ø С++.

Для объектов действует семантика присваивания по значению, поэтому никаких неожиданных эффектов не проявляется.

¨ Присваивание переменной типа класс значения переменной типа класс не даёт эффекта двух имен у одного хранилища данных. Оба хранилища были созданы по крайней мере ещё при объявлении этих переменных, и в присваиваниях каждое из них участвует независимо.

¨ Если параметр функции передается значением, а в качестве фактического параметра в вызове используется объект, то тоже получим ожидаемый результат, а не эффект передачи параметра ссылкой как в Object Pascal 2.

Это можно пронаблюдать тестированием, аналогичным вышеописанному для Object Pascal 2 – оно покажет ровно то, что и должно происходить при передаче параметра значением.

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

Однако это не означает, что в С++ по обсуждаемому вопросу полностью сохранена «дообъектная ситуация» и не призошло изменений в семантике понятий «переменная» и «присваивание» в связи с появлением классов и определяемых с их помощью динамических типов данных.

¨ Во-первых, семантика присваивания по значению предписывает так называемое «побитовое копирование» значения правой части присваивания в хранилище переменной левой части. При таком копировании, если компонент переменной имеет тип указатель, то он получает соответственно значение указателя, но данное, на которое он показывает, не копируется. Это данное с содержательной точки зрения в некотором смысле теперь будет частью значения двух переменных, той которую копировали и той куда копировали. Эта ситуация может спровоцировать трудно обнаруживаемые ошибки(*).

¨ Во-вторых, семантика присваивания по значению побитовым копированием в С++ действует на оператор присваивания, а для случаев

§ инициализации объектов другим объектом,

§ передачи параметров-объектов значением,

§ возвращения значения-объекта функцией

эта семантика действует только по умолчанию, а в общем случае действует семантика копирования, которая базируется на понятии конструктор копирования.

Конструктор копирования – это конструктор, имеющий точно один параметр - ссылку на объект этого же класса.

¨ Если в классе не объявлен конструктор копирования, то такой конструктор строится автоматически. Он создает объект и устанавливает его значение «побитовым копированием» значения своего фактического параметра.

¨ Конструктор копирования вызывается автоматически (неявно) в каждом из случаев:

§ при описании объекта с инициализацией другим объектом;

§ при передаче объекта в функцию по значению;

§ при возврате объекта из функции.

¨ Объявление конструктора копирования:

ИмяТипаКласс (const ИмяТипаКласс & prm);

Конструктор копирования вызывается неявно в вышеописанных ситуациях, а также явно, как и любой другой конструктор. При этом создается объект и выполняется тело конструктора, которое обычно устанавливает значение нового объекта (подходящим более полноценным способом, чем «побитовое копирование»).

... пока всё...

Program\PRGOOP\Project1.dpr

Program\C(C++)\prgoop\prgoopC.dsw

 


(*) Интуитивно достаточно ясно, что наличие памяти позволяет процессу: многократно повторять в выходном потоке некоторые данные входного, а также передавать некоторые данные в выходной поток не в том порядке, в котором они поступали из входного, например задерживать передачу одних данных, пропуская вперед другие.

(*) А возможно, в этом и есть их «истинная суть» по происхождению, содержанию и программистской трактовке.

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

(**) В общем случае, размер «окна просмотра» может со временем изменяться - скорость движения передней границы может иногда быть меньше или больше скорости движения задней границы окна.

(*) Синтаксические конструкции многомодульного программирования появились в «американских» языках даже раньше, чем в «европейских». В европейском языке AlgoL-60 ещё нет ничего такого, а в американском ForTran уже предусмотрена раздельная компиляция и для организации межмодульной связи имеется языковая конструкция common-блок.

(*) При большом желании эту ситуацию можно трактовать точно также как вариант объявления локальной переменной, но ощутимой пользы из такой трактовки не выжмешь...

(*) Идея последовательности и натурального ряда видимо происходит из нашего желания всегда иметь возможность от текущего перейти к «следующему» текущему. Так появляется «потенциально бесконечный счет», а далее «прибавить» и «умножить» - повторение и повторное повторение. Желание иметь обратную полноценно симметричную возможность - перейти к «предыдущему», дает идею «целых чисел» и далее «отнять». Но обращение операции «умножить» уже порождает идею рациональных чисел... с совсем непростым порядком на них... путем пополнения не просто приписыванием слева, как в случае отрицательных чисел, а «вставками»...

Однако вышеперечисленные желания можно в определенном смысле удовлетворить и другим «магическим» способом - замкнув конечную последовательность в кольцо. В арифметике «по модулю p» всего p чисел, операция «перейти к следующему» однажды «возвращает на круги своя». Однако имеются не только «прибавить» и «умножить», но и «отнять». А если p - простое число (еще одно «магическое» понятие), то и «умножить» обратимо.

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

(**) В стандарте Паскаль (и у Н.Вирта) эта операция называется GET.

(***) Read реализуется: PROCEDURE Read(VAR x: TVal; VAR F: TFile);

BEGIN x: =Retrieve(F); Next(F: TFile) END, а операции Retrieve в стандарте соответствует понятие «буферная переменная» - F^.

(*) которая имеется не только в случае файлов, но и в случае очередей - благодаря тому, что перезапоминанием можно в определенном смысле промоделировать «неразрушающее» чтение...

(*) см. гл.2. в А.В. Ахо, Дж.Д. Хопкрофт, Дж.Д. Ульман. Структуры данных и алгоритмы. М.: Вильямс, 2001. - 384 с.

(*) Стоит обратить внимание на то, что последовательность не обязана иметь элементы только простого и одинакового типа, а если её элементами могут быть последовательности, то мы имеем последовательность последовательностей, иначе говоря дерево...

(**) Муки, через которые прошла теория и методология программирования, в процессе рождения этого понятия ярко демонстрирует «родовое пятно» языка С – массивы, которые в языке имеются как структуры данных, но отсутствуют как тип данных.

(*) Сложно устроенные объекты, обычно имеют компоненты динамического типа (реализованные с использованием указателей), побитовое копирование сильно запутывает смысл присваивания для таких объектов.

Если посмотреть определения классов, например в библиотеке визуальных компонентов Borland, то сразу обращаешь внимание - в Delphi (Object Pascal 2) поля класса обычно имеют тип класс, а в C++Builder поля того же самого класса обычно объявлены указателями на класс. Этот технический приём позволяет унифицировать смысл побитового копирования полей класса, сделать его не зависящим от типа полей. Для так определенных классов семантика присваивания по значению фактически эквивалентна семантике присваивания по ссылке.






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.