т.е. если TObject — это корень иерархии объектов Delphi, то TClass — это метакласс этого класса. Читайте хелп и книжки по Delphi, а если вкратце, то...
В Delphi классы сами представляют собой особый вид объектов. Существуют т.н. классовые методы (class methods), которые можно вызывать в виде TMyClass.Something (не создавая экземпляр TMyClass). К классовым методам можно, в принципе, отнести конструктор (хотя тут со мной могут не все согласиться), т.к. он вызывается из класса, а не из объекта.
Экзмепляр (например, TClass) метакласса некоторого класса содержит все классовые методы соответующего класса (конструктор тоже).
К метаклассам тоже применимы понятия полиморфизма и наследования. Так, например, в Delphi существует механизм виртуальных конструкторов, что часто бесит C-шников
Пример:
Type
TBase = class (TObject)
constructor Create(); override; //В реализации пишем showmessage('TBase')end;
TBaseClass = class of TBase;
TDerived = class (TObject)
constructor Create(); override; //В реализации пишем showmessage('TDerived')end;
TDerivedClass = class of TDerived;
Procedure TForm1.Button1Click(Sender:TComponent);
Var
ClassRef: TBaseClass; //ссылка на класс (class reference).
//Фактически, это просто ссылка на экземпляр метакласса TBaseClass (или его потомка)begin
ClassRef:=TDerivedClass;
with ClassRef.Create() //вызываем конструкторdo Free; //Почистим за собой для порядкаend;
Будет выведено сообщение 'TDerived', т.к. по правилам полиморфизма и наследования хотя мы рассматриваем "объект" типа TDerivedClass как "объект" типа TBaseClass, но метод Create в TDerivedClass перекрыт, и поэтому вызывается именно он.
Если бы мы написали ClassRef:=TBaseClass, получили бы, ясное дело, 'TBase'.
Если бы мы не написали override в TDerived, получили бы опять 'TBase'.
Вот как выглядело бы содержимое TBaseClass и TDerivedClass в данном примере, если бы это были не метаклассы, а обычные классы:
TBaseClass = class (TClass) //наследуются все методы предкаconstructor Create() ; override; //создает экземпляр TBase (т.к. принадлежит TBaseClass)end;
TDerivedClass = class (TBaseClass)
constructor Create() ; override; //создает экземпляр TDerivedend;
Конструкторы здесь конструируют не TBaseClass и TDerivedClass, а TBase и TDerived.
Фу.. Объяснил чего-нибудь?
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Брр.. Невнимательно прочитал вопрос. Все гораздо хуже, оказывается
Класс описывает некий вид сущностей (например, кнопки в Windows). Объект — это конкретный экземпляр этого вида, конкретная сущность, какая-то конкретная кнопка. Найдите любую книжку по Delphi для начинающих и почитайте про объектно-ориентированное программирование.
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Здравствуйте, Slicer [Mirkwood], Вы писали:
SM>Брр.. Невнимательно прочитал вопрос. Все гораздо хуже, оказывается SM>Класс описывает некий вид сущностей (например, кнопки в Windows). Объект — это конкретный экземпляр этого вида, конкретная сущность, какая-то конкретная кнопка. Найдите любую книжку по Delphi для начинающих и почитайте про объектно-ориентированное программирование.
SM>Slicer
Короче класс это набор статических функций, виртуальных статических функций, с некой заполненной стркутурой информации о классе в том числе и VMT. Он же имеет конструкторы для создания экземпляра класса который представляет из — себя структуру первым полем которой (Self) есть ссылка на структуру информации о классе и затем (в Net отвечает за синхронизацию) идут уже поля объекта.
То есть информация о классе не изменна, а с объект по сути является ссылкой на структуру (Record) в куче.
и солнце б утром не вставало, когда бы не было меня
Уточнение: первое поле в экземпляре — указатель на VMT, а не на метакласс. Не берусь на память сказать, начинается ли представление метакласса с VMT, но, думаю, нет. Скорее, метакласс начинается по какому-то отрицательному смещению от VMT.
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
На самом деле, похоже, спрашивалось, чем Old-style классы (вводимые ключевым словом "object")отличаются от New-style ("class").
Так вот, old-style
1)поля и невиртульные методы в них располагаются так, как если бы это была структура
2)могут не иметь ссылку на VMT (если нет виртуальных методов)
3)сначала в памяти идет содержимое всех полей и адреса методов всех предков, в порядке наследования, а потом уже — то же для полей и методов, впервые появившихся в данном классе
4)поэтому если есть виртуальные методы, то добавляется и ссылка на VMT, но располагаться эта ссылка будет после всех унаследованных полей и методов из предков
Но это все касается реализации, а она обычно нас не волнует. Теперь — то, что относится к кодированию:
5)не могут содержать published-методов и свойств
6)к ним неприменима RTTI в том объеме, в котором она применима к new-style (операторы as, is). Однако применима функция TypeOf
7)они не могут реализовывать интерфейсы
8)они создаются при помощи new и удаляются по dispose
9)если при конструировании возникает Exception, то не происходит ни освобождения памяти, ни вызова деструктора
10)могут быть статическими, т.е. если мы напишем "var O:TMyObject", где "TMyObject=object constructor Init(); end;", то тем самым уже создается экземпляр. Правда, вызова конструктора не происходит Для динамического создания надо явно писать "var O:^TMyObject" и потом создавать "new(O, Init());"
Могу порекомендовать книгу Delphi in a Nutshell, там почти все это описано.
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
насамом деле в Borland Delphi Language Guide (for Delphi 7) написанно
что (переведу простыми словами )
объектные типы немогут иметь Published членов, они не наследуются от TObject (что иногда очень приятно )
можно создовать экземпляры в динамической памяти т.е. юзать New и Dispose, можно создовать как обычные переменные т.е. не вызывать конструктор перед этим т.е.
type
TMyObj = object
public
i: Integer;
end;
...
var
obj: TMyObj;
begin
obj.i := 1;
end;
так же написанно что Объектные типы поддерживаются только для backward compatibility и юзать их не рекомендуется.
Здравствуйте, Slicer [Mirkwood], Вы писали:
SM>Брр.. Невнимательно прочитал вопрос. Все гораздо хуже, оказывается
Все еще хуже, чем тот бред, который ты понаписал.
Человек четко спрашивает, чем отличаются две конструкции:
// 1.1 определение КЛАССА (ключевое слово CLASS!!!) в ДЕЛЬФИtype
TList = class(TObject)
...
end;
// 1.2 использование класса в дельфиvar
vList: TList;
...
begin
...
vList=TList.Create;
...
end// 2.1 определение ОБЬЕКТА (ключевое слово OBJECT!!!) в ДЕЛЬФИtype
TListObj = object
...
function GetVal: integer;
end;
// 2.2 использование ОБЬЕКТА в дельфиvar
vList: TListObj;
begin
...
writeln(vList.GetVal);
...
end;
На самом деле, все очень просто:
Свойства CLASS OBJECT
0. "Поддержка" в компиляторе ВСТРОЕНА ДЛЯ СОВМЕСТИМОСТИ
1. Общий предок ЕСТЬ НЕТ
2. Published видимость ЕСТЬ НЕТ
3. Конструктор и деструктор ЕСТЬ НЕТ
по умолчанию.
4. Переменная данного вида ССЫЛКА ВЕСЬ ОБЬЕКТ
5. Создание объекта данного Явный вызов Использование NEW
вида. конструктора
6. Уничтожение объекта Метод Использование DISPOSE
данного вида TObject.Free
(ну и еще
немного
способов)
7. Взятие и разыменование ЗАПРЕЩЕНО ТОЛЬКО ТЕМ И ЖИВЕМ
указателя на обьект данного
вида
8. Совместимость с ЕСТЬ НЕТ
интерфейсами
Короче, OBJECT — это идеологический предок CLASS, растущий из Turbo Pascal, к использованию не рекомендован ни под каким соусом.
Никогда не бойся браться делать то, что делать не умеешь. Помни, ковчег был построен любителем. Профессионалы построили Титаник...
SM>>Брр.. Невнимательно прочитал вопрос. Все гораздо хуже, оказывается VVP>Все еще хуже, чем тот бред, который ты понаписал.
Как все печально-то... Не буду комментировать откровенное хамство, прокомментирую лучше поразительное по своей глубине высказывание
VVP> Свойства CLASS OBJECT
VVP>7. Взятие и разыменование ЗАПРЕЩЕНО ТОЛЬКО ТЕМ И ЖИВЕМ
VVP>указателя на обьект данного
VVP>вида
Если ты не в состоянии даже взять указатель на new-style объект,
то зачем вообще тянуть руки к кнопкам + и — ?
var
p:pointer; //С таким же успехом может быть и ^TObject;
o:TObject;
begin
o:=TObject.Create();
p:=o; //или p:=@o, что то же самое
o:=TObject(p);
end.
Не думаю, что это — такое уж откровение...
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Здравствуйте, Slicer [Mirkwood], Вы писали:
SM>Как все печально-то... Не буду комментировать откровенное хамство,
За резкость прошу прощения, была вызвана трехкратным описанием тобой совершенно ненужных вещей. SM>прокомментирую лучше поразительное по своей глубине высказывание SM>
VVP>> Свойства CLASS OBJECT
VVP>>7. Взятие и разыменование ЗАПРЕЩЕНО ТОЛЬКО ТЕМ И ЖИВЕМ
VVP>>указателя на обьект данного
VVP>>вида
SM>
Все пучком, не гоните... SM>Если ты не в состоянии даже взять указатель на new-style объект, SM>то зачем вообще тянуть руки к кнопкам + и — ?
Ну хамство в ответ мог бы и не применять... Мир???? SM>
SM>var
SM> p:pointer; //С таким же успехом может быть и ^TObject;Никакого успеха быть не может! Компилятор не даст прострелить тебе ногу!
SM> o:TObject;
SM>begin
SM> o:=TObject.Create();
SM> p:=o; //или p:=@o, что то же самоеДа, что ты говоришь про "тоже самое"! Адрес от адреса <> адресу!
SM> o:=TObject(p);
Грязное приведение типа! Чему ты людей учишь???
SM>end.
SM>
SM>Не думаю, что это — такое уж откровение...
Здесь НЕТ операции взятия "@" указателя или операции разыменования "^" указателя!
Пункт 4 моего сравнения далего не так очевиден, как кажется. "Аналогичные" действия
с записями (record), такие как размещение записи на стеке, не требуют динамического размещения
памяти и для получения адреса записи требуется операция взятия адреса!
Никогда не бойся браться делать то, что делать не умеешь. Помни, ковчег был построен любителем. Профессионалы построили Титаник...
SM>>var
SM>> p:pointer; //С таким же успехом может быть и ^TObject;
VVP>Никакого успеха быть не может! Компилятор не даст прострелить тебе ногу!
См. далее
SM>> o:TObject;
SM>>begin
SM>> o:=TObject.Create();
SM>> p:=o; //или p:=@o, что то же самое
VVP>Да, что ты говоришь про "тоже самое"! Адрес от адреса <> адресу!
1) В Object Pascal уже давно существует неявная разадресация, и не только применительно к объектам
2) "То же самое" означает, что в обоих случаях значение p будет одинаково
SM>> o:=TObject(p);
VVP>Грязное приведение типа! Чему ты людей учишь???
Необходимая демонстрация возможности обратного преобразования. Но если использовать
var o:^TObject
то приведение не нужно.
SM>>end.
SM>>
var
p:^TObject;
o:TObject;
begin
o:=TObject.Create();
p:=@o;
o:=p^;
end.
Скажите мне, что это не компилируется в Delphi, и я принесу свои извинения. К сожалению, мне нечем проверять, кроме FPC, но он в режиме Delphi-совместимости вопроизводит даже обработку old-style классов, так что думаю, что и сейчас они с Delphi будут единодушны. Под FPC — работает. И под Delphi, считаю, тоже должно.
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Здравствуйте, Slicer [Mirkwood], Вы писали:
SM>См. далее
Смотрю... SM>1) В Object Pascal уже давно существует неявная разадресация, и не только применительно к объектам SM>2) "То же самое" означает, что в обоих случаях значение p будет одинаково
Не верно! См. ниже. SM>Необходимая демонстрация возможности обратного преобразования. Но если использовать SM>var o:^TObject SM>то приведение не нужно.
Мда... SM>
SM>Скажите мне, что это не компилируется в Delphi, и я принесу свои извинения. К сожалению, мне нечем проверять, кроме FPC, но он в режиме Delphi-совместимости вопроизводит даже обработку old-style классов, так что думаю, что и сейчас они с Delphi будут единодушны. Под FPC — работает. И под Delphi, считаю, тоже должно.
К моему величайшему удивлению, 5-ая дельфа это проглотила.
При этом значение p {2} стало адресом переменной o {0}, что не позволяет делать предположения об эквивалентности операторов "p:=@o" и "p:=o" (твое и 1-е, и 2-е утверждение).
Пункт 7 сравнения снимаю с повестки дня.
Никогда не бойся браться делать то, что делать не умеешь. Помни, ковчег был построен любителем. Профессионалы построили Титаник...
Здравствуйте, VVP, Вы писали:
VVP>При этом значение p {2} стало адресом переменной o {0}, что не позволяет делать предположения об эквивалентности операторов "p:=@o" и "p:=o" (твое и 1-е, и 2-е утверждение).
Упс, извини, и на старуху бывает проруха. Жаль нельзя самому себе минус влепить
Выходит, на сей раз Delphi таки поняли буквально и взяли адрес от указателя. Ну так достаточно сказать, что переменная типа TObject или его потомка сама по себе является указателем. В силу чего указатель на экземпляр брать не то что можно или нельзя, а просто не нужно, ибо он уже взят
И твой 7-й пункт можно не убирать, а переписать в соответствии с этим замечанием.
Slicer
Специалист — это варвар, невежество которого не всесторонне :)
Здравствуйте, Slicer [Mirkwood], Вы писали:
SM>Упс, извини, и на старуху бывает проруха.
Под вечер, чего только не померещется... SM>И твой 7-й пункт можно не убирать, а переписать в соответствии с этим замечанием.
Ладненько, спать пойду. Тебе спасибо, пока.
Никогда не бойся браться делать то, что делать не умеешь. Помни, ковчег был построен любителем. Профессионалы построили Титаник...
Всем большущее спасибо, на самом деле
нигде не мог найти инфу о типе object-именно тип
и его внутренности меня интересовали.
Теперь все прояснилось. Спасибо!!!
Здравствуйте, Slicer [Mirkwood], Вы писали:
SM>Уточнение: первое поле в экземпляре — указатель на VMT, а не на метакласс. Не берусь на память сказать, начинается ли представление метакласса с VMT, но, думаю, нет. Скорее, метакласс начинается по какому-то отрицательному смещению от VMT.
Метакласс начинается с отрицательного смещения. Я писал, что метаданные класса входит и VMT
А вот константы
{ Virtual method table entries }
Здравствуйте, kavlad, Вы писали: K>А когда например? Где эту особенность можно выгодно использовать ?
Там, где тебе жалко 4 байт на указатель на VMT. Для всяких штук типа Array[0..500000] of TMySmallType это может быть очень выгодно — и инкапсуляция на месте (public/private/protected работают) и перформанс на высоте. Так что можно дать рид-онли доступ к полю при помощи проперти (вопрос об обходе этого ридонли через (@Prop)^:=... оставляем на совести девелоперов Object Pascal) без потери производительности или памяти.
... << RSDN@Home 1.1.0 stable >>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, kavlad, Вы писали: K>>А когда например? Где эту особенность можно выгодно использовать ? S>Там, где тебе жалко 4 байт на указатель на VMT. Для всяких штук типа Array[0..500000] of TMySmallType это может быть очень выгодно — и инкапсуляция на месте (public/private/protected работают) и перформанс на высоте. Так что можно дать рид-онли доступ к полю при помощи проперти (вопрос об обходе этого ридонли через (@Prop)^:=... оставляем на совести девелоперов Object Pascal) без потери производительности или памяти.
Здравствуйте, Slicer [Mirkwood], Вы писали:
Не просто должно, а будет...
более того, TObject == Pointer с точки зрения совместимости типов (а при выключеной опции "Typed @ operator" ЛЮБОЙ указатель совместим с TObject.
на самом деле, одно из главных отличий классов Delphi от классов C++ — то, что их экземпляры (ну, если не использовать спец. подпрыгивания) ВСЕГДА распределяются на Хипе...
... << RSDN@Home 1.1.2 beta 1 >>
Если при компиляции и исполнении вашей программы не происходит ни одной ошибки — это ошибка компилятора :)))