Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Принцип работы конструторов

13K
18 января 2007 года
PavelX
20 / / 13.03.2006
Здравствуйте, друзья!
Вопросы к тем, кто понимает Делфи на глубоком уровне.

Вот у меня есть класс A, который унаследован от Tobject и класс В, который является потомком А. У них есть какие-то поля. В класс В добавлены поля.
1)Ни у А, ни у В не объявлены конструкторы. Что произойдет, если вызвать B.create? Какова будет цепочка вызовов?
2) У А объявлен и реализован конструтор. Что произойдет, если вызвать B.create? Какова будет цепочка вызовов? Будет ли вызван конструктор Tobject?

Заранее спасибо.
8
18 января 2007 года
mfender
3.5K / / 15.06.2005
Именно так и случится. Объекты создаются снизу-вверх. Т.е., будет вызван сначала конструктор объекта B, потом A и уж потом TObject. Если у объектов-наследников есть свой конструктор и нужно выполнить конструктор предка, это делается вс помощью inherited.
309
18 января 2007 года
el scorpio
1.1K / / 19.09.2006
Цитата:
1)Ни у А, ни у В не объявлены конструкторы. Что произойдет, если вызвать B.create? Какова будет цепочка вызовов?
2) У А объявлен и реализован конструтор. Что произойдет, если вызвать B.create? Какова будет цепочка вызовов? Будет ли вызван конструктор Tobject?


1. Конструктор есть всегда, как и деструктор - если программист его не объявляет вручную, компилятор создаёт автоматически.
2. Если только a производный от TObject. И если в объявляемых конструкторах будет вставлен вызов конструктора базового класса: inherited Create;

11K
18 января 2007 года
.nornad
125 / / 04.01.2007
Цитата: el scorpio
2. Если только a производный от TObject. И если в объявляемых конструкторах будет вставлен вызов конструктора базового класса: inherited Create;



Вообще-то, дефолтный конструктор родителя, о котором здесь и идёт речь, вызывается всякий раз при конструировании потомка. Сомневающиеся могут проверить, создав небольшую иерархию и производя в конструкторе запись какой-нибудь строки куда-нибудь в глобальную переменную (добавлением).

303
19 января 2007 года
makbeth
1.0K / / 25.11.2004
Цитата: el scorpio
1. Конструктор есть всегда, как и деструктор - если программист его не объявляет вручную, компилятор создаёт автоматически.
2. Если только a производный от TObject. И если в объявляемых конструкторах будет вставлен вызов конструктора базового класса: inherited Create;


Вот это в корне неверно. Объектная модель Delphi совсем непохожа на объектную модель C++. Ничего компилятор не создает автоматически. Утверждение, что конструктор есть всегда верно из-за того, что в Delphi все классы унаследованы от TObject, а в TObject конструктор есть.
Чтобы создать экземпляр класса, в случае отсутствия у него конструктора, вам придется вызвать один из (поскольку никто не запрещает создать несколько конструкторов, как, впрочем, и никто не заставляет называть их Create) конструкторов ближайшего класса-предка в иерархии, в котором есть конструктор (иначе вы попросту не сможете создать объект, поскольку синтаксис создания объекта предполагает явный указание имени конструктора).

Теперь о порядке вызова конструкторов.
Опять же здесь все не так как C++, где порядок вызова конструкторов неизменен TObject->A->B (в случае иерархии TObject<-A<-B). Delphi предлагает большую свободу. Небольшой пример номер раз:

Код:
//...

type
  B = class (A)
    MyField: Integer;
    constructor Create;
  end;

constructor B.Create;
begin
    MyField:=100; // Такое возможно - память уже выделена
    inherited; // Меняем порядок вызова конструкторов
end;
Небольшой пример номер два:
Код:
//...

type
  B = class (A)
    MyField1: Integer;
    MyField2: Integer;
    procedure MyMethod;
    constructor Create;
  end;

constructor B.Create;
begin
    MyField1:=100;
    MyMethod;
    inherited; // ;)
    MyField2:=MyField1 + 10;
end;
Ну и, наконец, небольшой пример номер три:
Код:
//...
 
type
   B = class (A)
     MyField1: Integer;
     MyField2: Integer;
     function MyMethod: boolean;
     constructor Create;
     constructor OtherCreate;
   end;
 
constructor B.Create;
begin
    MyField1:=100;
    if MyMethod then OtherCreate
    else inherited;
    MyField2:=MyField1 + 10;
 end;

constructor B.OtherCreate;
begin
    inherited Create;
    MyField2:=MyField1 + 15;
end;
Таким образом, модель Delphi является более гибкой.
С деструкторами тоже самое.
309
19 января 2007 года
el scorpio
1.1K / / 19.09.2006
Цитата:
Таким образом, модель Delphi является более гибкой.


Нихрена подобного. Всякая "либерализация" ведёт к увеличению бардака и нарушению нормальной работоспособности.
Хотя кое-что можно сделать и на С++, а то, что нельзя - просто ненужно.
Пример №1. Легко - через "список инициализации"
А вот примеры №2 и 3 легко могут привести к работе с неинициализированной областью памяти.

5
19 января 2007 года
hardcase
4.5K / / 09.08.2005
Цитата: el scorpio
Пример №1. Легко - через "список инициализации"
А вот примеры №2 и 3 легко могут привести к работе с неинициализированной областью памяти.


Память в Делфи выделяется до вызова Create и инициализируется Нулями. Всегда. Кроме того, всегда вызывается AfterConstruction после завершения работы любого конструктора.

309
20 января 2007 года
el scorpio
1.1K / / 19.09.2006
Цитата:
Кроме того, всегда вызывается AfterConstruction после завершения работы любого конструктора.


Пардон, только после завершения всех конструкторов - точнее, после завершения конструктора указанного класса.

Цитата:
Память в Делфи выделяется до вызова Create и инициализируется Нулями.


Тогда привести к обращению к нулевому указателю (ссылке), если вдруг (по какой-либое причине) вызовется метод базового класса :D

303
22 января 2007 года
makbeth
1.0K / / 25.11.2004
Цитата: el scorpio
Нихрена подобного. Всякая "либерализация" ведёт к увеличению бардака и нарушению нормальной работоспособности.
Хотя кое-что можно сделать и на С++, а то, что нельзя - просто ненужно.
Пример №1. Легко - через "список инициализации"
А вот примеры №2 и 3 легко могут привести к работе с неинициализированной областью памяти.


Видишь ли, это типичный ответ сишника :) Я и сам поначалу удивлялся такому поведению (сам изучал ООП на основе объектной модели C++), но потом в понял, что тут есть свои преимущества. Действительно, все эти возможности, которые я перечислил, зачастую приводят к трудноуловимым ошибкам, но при правильном использовании позволяют сделать очень интересные вещи...
К сожалению, при достаточной криворукости, даже объектная модель C++ не поможет :)
[quote=hardcase]Память в Делфи выделяется до вызова Create и инициализируется Нулями. Всегда. Кроме того, всегда вызывается AfterConstruction после завершения работы любого конструктора.[/quote]
При вызове любого конструктора у объекта уже инициализирована vmt, что позволяет в его теле вызывать виртуальные методы. Но и это еще не все :) Есть в Delphi такая штука, как классовые ссылки (фактически, ссылка на vmt класса, да к тому же конструктор в Delphi может быть виртуальным. Тут уж открываются такие возможности... :)

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог