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

Вниз

Странное поведение конструкции with ... do   Найти похожие ветки 

 
Толик   (2002-10-02 15:33) [0]

Столкнулся с такой проблемой:
Есть некая структура: не важно какая, например:

TMyStruct = record
Field1: longint;
Field2: byte;
end;

Далее, я хочу как-то инициализировать переменную, типа TMyStruct с использованием конструкции with. Эта переменная передаётся в ф-ю как var-параметр:

procedure Init(var MyStruct: TMyStruct);
begin
with(MyStruct)do begin
Field1 := 1;
Field2 := 2;
end;
end;

вылезает ошибка "Left side cannot be assigned to" хотя если убрать скобки, то всё работает.

procedure Init(var MyStruct: TMyStruct);
begin
with MyStruct do begin
Field1 := 1;
Field2 := 2;
end;
end;

А вот если объявить TMyStruct не как record, а как class, то работают оба примера. Если передавать MyStruct не по ссылке, а через указатель - тоже всё работает. Если обращатся к MyStruct как к глобальной переменно - тоже работает. А вот с var проблема. На это можно было бы и забить, если бы не ф-я TWinControl.CreateParams(var Params: TCreateParams). Как сие понимать? Это что баг Делфей???


 
Digitman   (2002-10-02 16:01) [1]

Может, и баг.

Ясно одно - компилятор ожидает явное приведение типа:

with TSomeOtherStruc(MyStruct)do begin
Field1 := 1;
Field2 := 2;
end;


 
McSimm   (2002-10-02 16:04) [2]

На первый взгляд такое поведение действительно кажется странным.

Однако объяснить это можно.

Дело в том, что для компилятора
MyStruct
и
(MyStruct)
разные вещи. Первое это переменная, второе - выражение, результатом которого является значение типа TMyStruct.


 
AlexT1000   (2002-10-02 16:05) [3]

with(MyStruct)do begin - а зачем это в скобки брать? смысл?





 
Best Before 2024   (2002-10-02 16:09) [4]

Вот более явный пример:

procedure MyXProc(var X : Integer);
begin
X := X + 1;
end;

procedure MyYProc;
var Y : Integer;
begin
Y := 0;
MyXProc(Y); //Ok
MyXProc((Y)); //[Error]: Constant object cannot be passed
// as var parameter
end;


 
Толик   (2002-10-02 16:36) [5]

Насчёт того, есть ли смысл подобное выражение брать в скобки - это просто привычка.

По логике вещей, если (MyStruct) действительно выражение (константное), то почему всё то же самое работает для классов?
Если объявить TMyStruct не record, а class, то оба примера компилируются без ошибок.


 
qube   (2002-10-02 16:39) [6]

Для классов работает, потому что экземпляры классов по указателю передаются


 
McSimm   (2002-10-02 16:53) [7]

>почему всё то же самое работает для классов?
Если результатом некоторого выражения является ссылка на экземпляр класса, мы вполне можем обращаться к членам этого класса:

(SomeClassVar).SomeField :=

Однако, обсуждаемая проблема может быть продемонстрирована таким примером:
SomeClassVar := TSomeClassVar.Create - нормально
(SomeClassVar) := TSomeClassVar.Create - ошибка


 
Толик   (2002-10-02 17:09) [8]

to qube © (02.10.02 16:39)
Допустим, если TMyStruct объявлен как класс, то в ф-ю
Init(var MyStruct: TMyStruct) по ссылке передаётся указатель на экземпляр. Если TMyStruct объявлен как record, то по ссылке передаётся сам экземпляр. Но как тогда объяснить такой факт: есть куча WinAPI"шных ф-й, параметрами которых являются указатели на структуру (так написано в хелпе и так работает в C++) Почему же тогда в Делфях надо передавать туда не Адрес объекта типа record, а сам этот объект??? Например:

function CreateProcess(... lpStartupInfo: TStartupInfo; ...);

но не

function CreateProcess(... lpStartupInfo: PStartupInfo; ...);
где
PStartupInfo = :TStartupInfo;

хотя на самлм деле передаётся туда адрес переменной а не переменная
Получается, что и record передаётся по указателю!


 
Игорь Шевченко   (2002-10-02 17:21) [9]

>Получается, что и record передаётся по указателю!

Все, что описано как var, гарантировано передается по указателю.
Все, что больше 8-х байт, гарантировано передается по указателю.


 
qube   (2002-10-02 17:23) [10]

Init(var MyStruct: TMyStruct) -- неявно передается адрес, где расположены поля структуры

Init(MyObj: TMyClass) -- неявно передается адрес, где расположен экземпляр объекта.

Init(var MyObj: TMyClass) -- неявно передается адрес, где расположен указатель на экземпляр объекта.


 
Digitman   (2002-10-02 17:38) [11]

>Толик

Смутившие тебя конструкции

function CreateProcess(... const lpStartupInfo: TStartupInfo; ...); stdcall;
и
function CreateProcess(... lpStartupInfo: PStartupInfo; ...); stdcall

будут скомпилированы одинаково, и фактический параметр передан по ссылке в обоих случаях. Обрати внимание на префикс const и соглашение о вызове stdcall.

Вот если бы вызов был декларирован так
function CreateProcess(... lpStartupInfo: TStartupInfo; ...);
компилятор поступил бы иначе : передал бы факт.параметр по значению, "натолкав" значения полей структуры в стек непосредственно перед вызовом.


 
Digitman   (2002-10-02 17:42) [12]

Скажу более - и в случае

function CreateProcess(... const lpStartupInfo: TStartupInfo; ...);

параметр будет передан по ссылке (но результат - сам понимаешь, какой будет)


 
Толик   (2002-10-02 18:03) [13]

Огромное спасибо всем принявшим участие в обсуждении!
Если не возражаете, то продолжим завтра. У меня есть ещё пара вопросов по поводу обсуждаемой темы, а сейчас уже домой пора :)



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

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

Наверх





Память: 0.48 MB
Время: 0.007 c
14-45573
Gumanoid
2002-08-28 15:48
2002.10.14
Доступ к реестру


1-45401
Dmitriy Polskoy
2002-10-03 10:37
2002.10.14
Так же как и FlashGet


1-45340
maxinfosoft
2002-10-05 15:46
2002.10.14
Как вставить кнопку в MS Word и обработать нажитие на нее?


3-45179
Punisher
2002-09-22 12:11
2002.10.14
SQL Explorer


3-45221
vich
2002-09-23 22:00
2002.10.14
Как прописать файлы библиотек в программе?





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский