Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2002.10.14;
Скачать: CL | DM;

Вниз

Странное поведение конструкции 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;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.018 c
1-45347
Kolya
2002-10-02 02:28
2002.10.14
Array


1-45420
oleg_er
2002-10-02 15:11
2002.10.14
EXCEL - не хочет вставлять строки


3-45203
Rustik
2002-09-23 13:14
2002.10.14
Мастера помогите имеются две таблицы Родитель-Дочернее пытаюсь


14-45534
Poirot
2002-09-19 16:43
2002.10.14
Сотик. Какой лучше!!!


3-45196
Sherlock99
2002-09-23 10:52
2002.10.14
Перенос заголвков столбцов в DBGrid?