Форум: "Основная";
Текущий архив: 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