2012-02-28 3 views
2

Нижеприведенный проект не работает с ошибкой «нарушение прав доступа». Я использую Delphi XE2 Update 3.Ошибка компилятора Delphi или моя ошибка?

program Project1; 

{$APPTYPE CONSOLE} 

type 
    TTestClass = class 
    public 
    class procedure Test; 
    end; 

var 
    TestClass: TTestClass; 

class procedure TTestClass.Test; 
begin 
end; 

begin 
    TestClass.Test; 
end. 

Если я пометить class procedure Test как "статический", нет никаких проблем. Является ли это «разработанным»?

P.S .: Это была моя ошибка, стыдно за меня.

+5

«Позор вам»? Может быть. Но, по крайней мере, вы были достаточно скромны, чтобы считать, что это может быть ваша ошибка, а не ошибка компилятора, и спросите людей, которые знают больше, чем вы. Поздравляю за это; это одна из замечаний хорошего инженера. –

ответ

7

Да, то, что вы видели, является правильным.

Нестатические методы класса, как и методы экземпляра, имеют скрытый параметр Self. Для методов класса, относящихся к заданию класса . Это как компилятор преобразует ваш метод в этом:

type 
    TTestClassClass = class of TTestClass; 

procedure TTestClass_Test(Self: TTestClassClass); 

При вызове методы класса на неклассовый приемнике (т.е. ссылки на объект), компилятор вставляет вызов ClassType для заполнения этого параметра с время выполнения тип объекта, например:

TTestClass_Test(TestClass.ClassType); 

метод ClassType извлекает адрес VMT объекта, но переменная не относится к какой-либо ВМТ. Ваша переменная является либо нулевым указателем, либо неинициализирована, поэтому попытка разыменовать ее для чтения адреса VMT приводит к нарушению доступа, если вам повезет. (Если вам не повезло, он разыскивает адрес, и адрес оказывается где-то еще в адресном пространстве вашей программы, и результат интерпретируется как указатель VMT, даже если это не так.)

Методы класса вызова в ссылках на классы или действительные ссылки на объекты.

TTestClass.Test; 

При вызове его на класс-ссылки «буквальным», как указано выше, компилятор уже знает значение первого параметра и преобразует вызов так:

TTestClass_Test(TTestClass); 
1

Вы вызываете метод по ссылке nil. Даже методы класса используют объект, для которого они вызывают, для определения реального типа переменной во время выполнения. Вы должны сделать

TestClass := TTestClass.Create; 

Чтобы реально создать экземпляр класса, то

FreeAndNil(TestClass); 

Чтобы освободить его.

Если вы

TTestClass.Test; 

Тогда вызов во время компиляции, потому что она не зависит от типа переменной, поэтому она работает.

+0

Действительно ли мне нужно создать экземпляр класса для доступа к процедуре класса? – BofA

+0

-1 Какой смысл быть процедурой класса, если вам нужно создать экземпляр класса для его вызова? – ComputerSaysNo

+0

На самом деле, мои плохие, не прочитали весь код, он объявляет переменную типа ... – ComputerSaysNo

0

Проблема в том, что, хотя у вас есть объявленная переменная вашего TTestClass, у вас нет экземпляра. Вам нужно вызвать Create, прежде чем cn использовать метод Test, иначе он будет терпеть неудачу (за исключением вашего статического, который не нуждается в создании экземпляра всего класса). Таким образом, ваш основной код будет

begin 
    TestClass := TTestClass.Create; 
    TestClass.Test; 
    TestClass.Free; 
end. 
0

Следующие работает отлично в XE, это похоже на ошибку в вашей версии Delphi, ваш код верен, пока он не вызывает «закрытую» переменную внутри класса, которая не является экземпляром, но я думаю, вы поняли это.

program Project1; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

type 
    TTest = class 
    public 
    class procedure test; 
    end; 

{ TTest } 

class procedure TTest.test; 
begin 
    Writeln('hello'); 
end; 

begin 
    try 
    TTest.test; 
    Readln; 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
end. 
+0

OP не использует 'TTest.test', он вызывает Test mehthod, используя унифицированную переменную' TestClass.Test' – RRUZ

+0

Это работает во всех версиях Delphi, но тогда это отличается от кода в вопросе. –

+0

@RRUz, Дэвид, да, я прочитал его код в «спешке» и сделал плохой ответ ... Я понял, что было уже слишком поздно ... – ComputerSaysNo

2

Звучит разумно. TestClass равен нулю. Вы не можете вызывать метод нестатического класса для не-экземпляра:

«Метод класса можно вызвать через ссылку на класс или ссылку на объект. Когда он вызывается через ссылку на объект, класс объекта становится значением Self '- no object, no class.

«Статические методы класса могут быть доступны без ссылки на объекты» - не имеет значения в экземпляре TestClass из-за прямого статического вызова метода класса.

Смежные вопросы