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

Вниз

Вопрос насчет Create и Destroy   Найти похожие ветки 

 
Giemgo   (2003-04-13 16:37) [0]

Посмотрел реализацию конструктора и деструтора у базового класса:

constructor TObject.Create;
begin
end;


destructor TObject.Destroy;
begin
end;

procedure TObject.Free;
begin
if Self <> nil then
Destroy;
end;


И не понял, а зачем их переопределять ? Они же ничего не делают. А метод free вообще непонятен. Он вызывает Destroy, который ничего не делает и в тоже время зачем тогда проверяет Self ?

Ничего не понимаю.


 
default   (2003-04-13 16:42) [1]

чё тут сложного ?
Free введён для безопасности перед вызовом деструктора он проверяет не равен ли nil-у объект(точнее указатель на объект)
а что в Create и Destroy ничего не написано это ничего страшного
инициализировать нечего в базовом классе
а сами действия по выделению памяти, освобождению и других операций выполняются неявно(их генерит компилятор)


 
Giemgo   (2003-04-13 16:48) [2]

Ага. Ясно.

А когда выпонляются эти неявные действия ? Перед Create и после Destroy соответственно ?


 
default   (2003-04-13 17:00) [3]

ну и так не сложно догадаться
мы пишем код в констукторе когда сам объект уже создан
(Self - действителен)
а уничтожается объект естественно после нашего кода в деструкторе


 
Giemgo   (2003-04-13 17:08) [4]

Ну, блин, я уж просто не знаю. В последнее время только и наталкиваюсь на скрытости. Скрытый передаваемый параметр, скрытый код. Может там после Destroy еще какой метод скрыто вызывается.

Вообще не понимаю, зачем это так ? Уж пусть было бы все наглядно, чтоб все можно было посмотреть. Пусть я этого и не пойму, но хоть буду видеть, что это есть...
ну вообще это в борланд надо писать :)


 
Anatoly Podgoretsky   (2003-04-13 17:43) [5]

Giemgo (13.04.03 16:37)
С чего ты решил, что ничего не делает, он же виртуальный!

Одна из парадигм ООП это черный ящик, тебе не надо знать что там внутри, оно еще и вредно.

Книги тебе надо почитать умные, например Пачеко и Текстейру.


 
Giemgo   (2003-04-13 18:01) [6]

1) Как понимаю, эти неявные операции включаются по ключевым словам constructor/destructor ?

2) TObject.Create просто указывает, что конструктор должен называться Create ? (нельзя ведь создать класс, чтоб его предком не являлся TObject)

3) а как насчет inherited ?

Сначала выделяется память под объект, потом выполняется конструктор. А если я в конструкторе вызову с помощью inherited конструктор предка ? Память же не будет второй раз выделяться ?

А если я вызову конструктор предка без inherited ?

4) А почему это Create возвращает ссылку на экземпляр ?

Тогда он должен был быть описан так:

constructor TObject.Create: Pointer;
--------------------------------------------------------

С чего ты решил, что ничего не делает, он же виртуальный!

Одна из парадигм ООП это черный ящик, тебе не надо знать что там внутри, оно еще и вредно.


Да я блин вообще не понимаю ! :(((
Ну что это за объявление
TObject = class;

И все ! Как это так, нету объявления конструктора Create, но зато есть реализация TObject.Create

И вообще, если TObject = class, то он должен наследоваться от TObject, так как любой объявленный класс без указания предка по умолчанию наследуется от TObject. Разве не так ?

вообщем, я запутался полностью...

Книги тебе надо почитать умные, например Пачеко и Текстейру.

Ну вот только этого не надо. Не знаю, почему на половину вопросов люди отвечают "почитай Пачеко и Тейксера". Книга хорошая - спору нет, но там про концепции VCL написано КРАЙНЕ мало, практически ничего. Там даже про полиморфизм написано, что, мол, используйте override для переопределения метода. Никакого разъяснения, что такое VMT даже не упоминается.

Я как понимаю, этот мой вопрос, как и многие другие, раскрыты в книге Конопко (насколько я слышал о чем эта книга). Только я вот найти ее нигде не могу. А электронные версии - это...


 
Anatoly Podgoretsky   (2003-04-13 18:15) [7]

Ну тогда почитай Буча, если эта для тебя слава.
Твой вопрос не ракрыт в книге Конопки, эта книга посвящена созданию компонент, а не основам ООП и Дельфи. В электроном виде ее дейтвительно нет.


 
Юрий Зотов   (2003-04-13 18:16) [8]

> Giemgo (13.04.03 17:08)

> И не понял, а зачем их переопределять ?
> Они же ничего не делают.

Для того, чтобы класс TObject не был абстрактным. Иначе их пришлось бы писать в каждом его потомке. А так - не нужно. Ну, не делают они ничего в ЭТОМ классе, ну и что? Зато они что-то делают в его потомках, и все прекрасно стыкуется. Полиморфизм, однако...


> Может там после Destroy еще какой метод скрыто вызывается.

Обязательно. Точнее, не ПОСЛЕ Destroy, а ИЗ Destroy. Метод FreeInstance. Иначе как же уничтожить объект? Ведь в коде самих деструкторов нигде нет освобождения памяти.

И из конструктора тоже неявно вызываются методы NewInstance и InitInstance. Иначе как же создать и проинициализировать объект? Ведь в коде самих конструкторов нигде нет ни выделения памяти, ни ее очистки.

Чтобы все стало понятно, перекройте в форме конструктор и деструктор (напишите там что угодно), поставьте в них BreakPoint"ы, а при остановке не них вызовите окно CPU и просмотрите реальный ассемблерный код. Увидите все неявные вызовы. Посмотрите в модуле System, что они делают - поймете их логику. Думаю, после этого Вам снова захочется написать в Borland - чтобы выразить свое восхищение красотой и самой идеи, и ее реализации. А также, чтобы поблагодарить за то, что они избавили своих пользователей от рутинной работы. А заодно и от лишних ошибок в коде.


 
Giemgo   (2003-04-13 18:40) [9]

Юрий Зотов, да, согласен, все понятно.

Но как насчет

1) TObject = class;

И все ! Как это так, нету объявления конструктора Create, но зато есть реализация TObject.Create


2) А почему Create возвращает ссылку на экземпляр ?

Тогда он должен был быть описан так:

constructor TObject.Create: Pointer;


 
vuk   (2003-04-13 20:47) [10]

to Giemgo:
>Но как насчет
>1) TObject = class;
Это т.н. опережающее объявление(forward declaration) класса. Сам класс описан ниже по тексту в модуле system. Опережающие объявления обычно используются, когда нужно разрешить ссылки на экземпляры класса. Следующий пример будет выдавать ошибку при компиляции без опережающего объявления.

type
TAnotherClass = class;

TSomeClass = class
FReference : TAnotherClass;
end;

TAnotherClass = class
FReference : TSomeClass;
end;

>2) А почему Create возвращает ссылку на экземпляр ?
>Тогда он должен был быть описан так:
>constructor TObject.Create: Pointer;
Не должен. Конструктор, хотя и возвращает ссылку на созданный экземпляр, описывается именно как метод, не возвращающий значения. Это делается потому, что результат, возвращаемый конструктором соответствует типу класса, для которого он вызывается. То есть конструктор TObject возвращает TObject, а конструктор унаследованного класса, будет возвращать уже другой тип данных(даже если конструктор не переопределялся). Если бы результат описывался явно, то необходимо бы было заново описывать все конструкторы, чтобы они возвращали нужный результат.


 
Giemgo   (2003-04-13 22:04) [11]

vuk, ясно. Спасибо


 
Юрий Зотов   (2003-04-13 23:46) [12]

> 2) А почему Create возвращает ссылку на экземпляр ?

Не всегда. Он создает новый экземпляр и возвращает ссылку на него, если был вызван, как классовый метод - через ссылку на класс:
NewMyClassInstance := TMyClass.Create(...).

Если же конструктор был вызван, как обычный метод класса:
inherited Create(...)
то просто отрабатывает его код, но никакой новый экземпляр при этом не создается.

Просто слово "constructor" (как и "destructor") для компилятора является ключевым (а не просто "procedure" или "function"), по которому он и строит специальный, а не обычный код.


 
Giemgo   (2003-04-14 11:38) [13]

1) То есть, получается если в программе есть вызов [Какой_То_Класс].Create, то создается дополнительный код в виде вызова NewInstance, InitInstance.

Если вызов inherited Create то дополнительный код не создается ?

2) а когда вызывается inherited Create, как обработчик Create предка определяет, что инициализируемые переменные относятся к потомку ? То есть, видимо, в Create должна передаваться ссылка на экземпляр ?

Ну вот допустим, есть даже не конструктор, а просто метод:

procedure TSomeClass.SomeMethod;
begin
i:=5; // свойство класса
end;

Если я в потомке вызываю:

procedure TInheritedClass.SomeMethod;
begin
inherited SomeMethod
end;

то как TSomeClass.SomeMethod определяет, что нужно инициализировать переменную именно у экземпляра TInheritedClass ?


 
Anatoly Podgoretsky   (2003-04-14 12:14) [14]

Есть такое понятие как Self


 
Юрий Зотов   (2003-04-14 12:18) [15]

Он не определяет. Ему это и не нужно. Он просто инициализирует переменную i, которая есть у ОБОИХ классов. И все получается тип-топ.

Наследование, однако...


 
Giemgo   (2003-04-14 18:54) [16]

Блин. Опять не догоняю.

Вот тут написал код:

type
TSomeClass = class
i:integer;
procedure ChangeI;
end;

TInheritedClass = class (TSomeClass)
i:string;
end;

...

procedure TSomeClass.ChangeI;
begin
i:=5;
end;

...

procedure TForm1.Button1Click(Sender: TObject);
var T:TInheritedClass;
begin
T:=TInheritedClass.Create;
T.ChangeI;
T.Free ;
end;


Компилятор даже предупреждения не выдал !

Странно.

С учетом фразы:

Он просто инициализирует переменную i, которая есть у ОБОИХ классов. И все получается тип-топ. Наследование, однако...

Какую же он i инициализирует ? Да, она есть в обоих классах, только там она integer, а здесь string !!!!


 
default   (2003-04-14 20:16) [17]

A field is like a variable that belongs to an object. Fields can be of any type, including class types. (That is, fields can hold object references.) Fields are usually private.
To define a field member of a class, simply declare the field as you would a variable. All field declarations must occur before any property or method declarations. For example, the following declaration creates a class called TNumber
whose only member, other than the methods is inherits from TObject, is an integer field called Int.

type TNumber = class

Int: Integer;
end;

Fields are statically bound; that is, references to them are fixed at compile time. To see what this means, consider the following code.

type

TAncestor = class
Value: Integer;
end;

TDescendant = class(TAncestor)

Value: string; // hides the inherited Value field
end;

var

MyObject: TAncestor;

begin

MyObject := TDescendant.Create;
MyObject.Value := "Hello!"; // error
TDescendant(MyObject).Value := "Hello!"; // works!
end;

Although MyObject holds an instance of TDescendant, it is declared as TAncestor. The compiler therefore interprets MyObject.Value as referring to the (integer) field declared in TAncestor. Both fields, however, exist in the TDescendant object; the inherited Value is hidden by the new one, and can be accessed through a typecast.

читай хелп
поле перекрывается наследником если имеет тоже имя
а на счёт ChangeI - по ходу он игнорится...


 
Giemgo   (2003-04-14 21:02) [18]

По ходу игнорится ? Хм... как это ?

В программировании нет "по ходу"


 
vuk   (2003-04-14 21:55) [19]

Ничего не игнорируется. ChangeI описан в TSomeClass и поэтому у него есть доступ к переменной, которая становится невидимой в наследнике.


 
Giemgo   (2003-04-14 22:15) [20]

vuk, ага. То есть, создавая экземпляр TInheritedClass я трачу лишнюю память на I:integer, праильно ? Хотя к ней можно обратиться, как TSomeClass(T).i ?


 
vuk   (2003-04-14 22:18) [21]

Нет. От того, что поле не доступно по имени, оно не прекращает существование. Оно по прежнему существует и занимает память. Просто обратиться к нему в TInheritedClass по имени нельзя.


 
default   (2003-04-14 22:41) [22]

Сам же написал что к i наследуемой от предка можно обратиться как TSomeClass(T).i почему тратишь? сам себя не понимаешь хе


 
vuk   (2003-04-14 22:46) [23]

>vuk © (14.04.03 22:18)
>Нет.
Ож блин! Совсем я заработался... :o) Вместо ДА написал НЕТ. :o)


 
Giemgo   (2003-04-15 00:02) [24]

default, ну внешне можно. А как обратиться, допустим, из какого-либо метода TInheritedClass к этой переменной ?


 
default   (2003-04-15 01:08) [25]

program Project2;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TSomeClass = class
i: Integer;
end;

TInheritedClass = class(TSomeClass)
i: String;
procedure SetIPredka(const Value: Integer);
procedure WriteIPredka;
end;

procedure TInheritedClass.SetIPredka(const Value: Integer);
begin
TSomeClass(Self).i := Value
end;

procedure TInheritedClass.WriteIPredka;
begin
WriteLn(IntToStr(TSomeClass(Self).i))
end;

var
T: TInheritedClass;

begin

T := TInheritedClass.Create;
T.SetIPredka(19); // меняем "i" предка
T.WriteIPredka; // 19
T.Free;
ReadLn

end.


так "катит"


 
default   (2003-04-15 01:14) [26]

"// меняем "i" предка"
под этим я подразумеваю что меняем значение переменой "i"
наследуемой от TSomeClass


 
Giemgo   (2003-04-15 15:54) [27]

default, блин. О self то я забыл. Лапоть



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

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

Наверх




Память: 0.53 MB
Время: 0.007 c
3-91168
TempAlly
2003-04-09 14:18
2003.04.28
Date-константа в TQuery.Filter


14-91450
Sergey
2003-04-11 11:29
2003.04.28
PHP скрипт конвертации базы Dbf->Oracle


14-91521
Тимохов
2003-04-10 19:49
2003.04.28
Почитал тут фак, и не нашел там раздела с (+)


11-91238
SPeller
2002-07-20 10:51
2003.04.28
Глюк в тулбаре ?


14-91548
zx
2003-04-10 15:11
2003.04.28
Upgrade DBE или как запугать User’а : )





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