(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Нельзя, но можно в Delphi, или аномалии Delphi и почему это работает

Источник: RSDN Magazine #6-2004

Меня заинтересовал один момент в Delphi - почему, когда я забываю создать объект класса, программа вываливается, тем не менее, только внутри метода?

Я решил протестировать эту особенность в различных вариациях:

TForm1

type
  TSomeClass = class (TObject)
  private
    FProperty : Integer;
    function SomeFunc(pParam : Integer; var pSelf : TSomeClass) : Integer;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  xObj : TSomeClass;
  x, y : Integer;
begin
  x := StrToInt(Edit1.Text);
  xObj.SomeFunc(x, xObj);
  y := xObj.FProperty;
  xObj.Free;
  Edit2.Text := IntToStr(y);
end;

function TSomeClass.SomeFunc(pParam : Integer; var pSelf : TSomeClass): Integer;
var
  i : Integer;
begin
  Self := TSomeClass.Create;
  pSelf := Self;
  Result := 0;
  for i := 1 to pParam do
    Result := Result + i;
  FProperty := Result;
end;

Приведенный код компилируется и работает абсолютно без ошибок (по крайней мере, в Delphi 6). Почему? Сейчас будем разбираться.

Обратите внимание на описание следующего класса:

TSomeClass

  TSomeClass = class (TObject)
  private
    FProperty : Integer;
    function SomeFunc(pParam : Integer; var pSelf : TSomeClass) : Integer;
  end;

И свойство, и метод его объявлены как private. Но, тем не менее, следующий код вполне замечательно компилируется:

TForm1.Button1Click

procedure TForm1.Button1Click(Sender: TObject);
var
  xObj : TSomeClass;
  x, y : Integer;
begin
  x := StrToInt(Edit1.Text);
  xObj.SomeFunc(x, xObj);
  y := xObj.FProperty;
  xObj.Free;
  Edit2.Text := IntToStr(y);
end;

Как видно, доступ к свойству и методу абсолютно свободен. Но это - широко известная аномалия защиты Delphi, заключающаяся в том, что код имеет доступ ко всем (даже приватным) данным и методам классов, описанных в том же модуле.

Далее - более интересный момент. Во второй строчке вызывается метод несуществующего объекта! Это уже хитрость, связанная с особенностью компиляции классов. Дело в том, что при компиляции класса в код все имеющиеся у него функции сразу компилируются в функции с неявным аргументом - ссылкой Self. Так вот, этот Self и есть ссылка на память, отведенную под член-данные объекта. И эта память выделяется при вызове функций, помеченных как constructor, и высвобождается при вызове функций, помеченных как destructor! Получается, что все методы в объекте - это почти методы классов (Class methods, в терминологии Delphi), за исключением параметра Self! Т. е. разница между ними только в синтаксисе вызова и в неявном параметре. Деструкторы отличаются от них тем, что неявно содержат код освобождения памяти. Соответственно, конструкторы не содержат Self как аргумент, но возвращают его после выделения памяти под данные объекта.

Теперь давайте сфокусируемся на методе класса:

TSomeClass.SomeFunc

function TSomeClass.SomeFunc(pParam : Integer; var pSelf : TSomeClass): Integer;
var
  i : Integer;
begin
  Self := TSomeClass.Create;
  pSelf := Self;
  Result := 0;
  for i := 1 to pParam do
    Result := Result + i;
  FProperty := Result;
end;

Он содержит одну локальную переменную, память под которую опять же выделяется при компиляции класса! Теперь мы создадим объект класса стандартным конструктором и присвоим Self ссылку на этот объект. Опять всё работает! Delphi позволяет модифицировать переменную Self! Именно это и позволяет написать последнюю строчку в этой функции, ведь теперь-то память под данные у нас выделена! Ссылку на эту область памяти мы и вернём через параметр pSelf.

Вернёмся опять к процедуре TForm1.Button1Click. Так как после вызова метода xObj.SomeFunc(x, xObj) переменная xObj содержит ссылку на выделенную область памяти, доступ к xObj.FProperty у нас уже есть - мы получили от операционной системы 4 байтика, требуемые для ее хранения. Поэтому y := xObj.FProperty работает тоже без проблем. Ну и, наконец, xObj.Free возвращает взятую нами память обратно операционной системе. После этого, несмотря на то, что там лежат вычисленные нами данные, доступа туда у нас уже нет (обращение к xObj.FProperty будет вызывать ошибку доступа к памяти Access Violation). Именно поэтому программа падает уже внутри методов, даже если память под объект не была выделена.

Эту статью ни в коем случае нельзя рассматривать, как призыв пользоваться этими аномальными особенностями Delphi, просто автор надеется, что она поможет вам в дальнейшем выловить те ошибки, которые сама Delphi поймать никак не может.

Ссылки по теме


 Распечатать »
 Правила публикации »
  Обсудить материал в конференции Micro Focus/Borland » [2]
Написать редактору 
 Рекомендовать » Дата публикации: 12.02.2007 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Radmin 3.x - Стандартная лицензия 1 компьютер
Nero Platinum 2018 VL 5 - 9 License corporate
Avira Internet Security Suite, 1 ПК, 1 год
VideoStudio X9 ULTIMATE. Электронный ключ.
IBM DOMINO ENTERPRISE CLIENT ACCESS LICENSE AUTHORIZED USER ANNUAL SW SUBSCRIPTION & SUPPORT RENEWAL
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
СУБД Oracle "с нуля"
Программирование на Visual Basic/Visual Studio и ASP/ASP.NET
Все о PHP и даже больше
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
Обсуждения в форумах
Пишу программы на заказ профессионально (2412)
Пишу программы на заказ на языках Pascal (численные методы, списки, деревья, прерывания) под...
 
Пишу программы на заказ для студентов (192)
Пишу для студентов на с, с++, паскаль в средах ms visual studio, qt, builder, borland c, delphi....
 
Excell не печатает :-( (2)
Почему то Excell не печатает страницы в альбомной ориентаций, то есть страница в аольбомной...
 
Пишу программы на заказ (1)
Пишу на языках C#, VB.NET, VBA с использованием WPF, WCF, SQL.
 
Программист для удалённой работы (ASP.NET MVC, C#, MSSQL, AJAX) (2)
предлагаю услуги по разработке web-приложений с использованием таких технологий, как: ASP.NET...
 
 
 



    
rambler's top100 Rambler's Top100