2010-05-19 4 views
3

Насколько я знаю - подпрограммы с приватным режимом доступа к его родительскому подключению/процедуре, правильно?Доступ к вспомогательным функциям/процедурам из DPR или других функций/процедур в Delphi

Есть ли способ доступа к ним из «внешнего мира» - dpr или другой функции/процедуры в блоке?

Кроме того - в каком формате требуется больше вычислений и пространства для скомпилированного файла?

, например:

function blablabla(parameter : tparameter) : abcde; 
procedure xyz(par_ : tpar_); 
begin 
    // ... 
end; 
begin 
// ... 
end; 

procedure albalbalb(param : tparam) : www; 
begin 
xyz(par_ : tpar_); // is there any way to make this function public/published to access it therefore enabling to call it this way? 
end; 

// all text is random. 

// also, is there way to call it from DPR in this manner? 

// in C++ this can be done by specifing access mode and/or using "Friend" class .. but in DELPHI? 
+0

Частный частный :) Вы ищете способ сделать его общедоступным без изменения кода? – mjn

+0

Это даже не личное, это внутреннее. Он не существует вне «родительской» процедуры, где он встроен. –

ответ

5

Примечание: встроенные процедуры <> Частные/защищенные методы.

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

Вот еще один пример:

procedure DoThis; 

function DoThat : Boolean; 
begin 
    // This Routine is embedded or internal routine. 
end; 
begin 

// DoThat() can only be accessed from here no other place. 

end; 

Независимо от видимости, методы на классах, можно вызвать с помощью Delphi 2010 с помощью RTTI. Я подробно рассказал, как это сделать в this article.

Если вы находитесь в одном и том же методе Единицы, класс может быть доступен любым другим кодом независимо от видимости, если только они не отмечены строгим приватным. This Question имеет более подробную информацию и хороший пример кода в accepted answer.

Если вы используете два разных устройства, вы можете использовать Защищенный метод Hack для доступа к защищенным методам. Это подробно описано в this article.

2

Нет, нет никакого способа, чтобы сделать то, что вы просите. Функция xyz можно назвать только прилагаемой функцией blablabla. За пределами этой функции xyz не имеет возможности, и назвать его невозможно. Если C++ допускает вложенную функцию, не было бы никакого способа ссылаться на нее, так же как нет способа ссылаться на функции со статической связью извне текущей единицы перевода.

Если вам нужно позвонить по телефону xyz с внешней стороны функции blablabla, тогда переместите xyz на улицу. Если вам нужно вызвать его извне текущего устройства, вам необходимо объявить эту функцию в разделе интерфейса устройства. Затем добавьте этот блок в предложение uses внешнего кода, и вы можете позвонить по номеру xyz из любого места, куда вы хотите, даже в файл DPR.

Если xyz относится к переменным или параметрам функции blablabla, тогда вам необходимо передать их в качестве параметров, так как xyz больше не будет иметь к ним доступа.

Концепция спецификаторов доступа здесь не имеет особого значения, поскольку мы не говорим о классах. Блоки имеют интерфейс и реализация секций, которые не являются на самом деле так же, как общественного и частные секции класса.

7

Вложенные процедуры/функции, объявленные внутри другой процедуры или функции, являются специальным типом, поскольку они могут обращаться к стеку (и, следовательно, к параметрам/локальным переменным) процедуры, в которую они вложены. Из-за этого и Delphi не существует способа доступа к ним за пределами «родительской» процедуры. Вы используете их только в том случае, если вам нужно воспользоваться их специальными функциями. AFAIK Delphi/Pascal - один из немногих языков, на котором есть эта функция. С точки зрения компилятора у вызова есть дополнительный код, позволяющий получить доступ к кадру родительского стека, IIRC. Класс/функции AFAIK «друг» в C++ различны - они являются методами доступа к классу, в то время как в вашем примере вы используете простые процедуры/функции. В Delphi все процедуры/классы, объявленные в том же блоке, автоматически «друг», если только строгие частные объявления используются в последних выпусках Delphi. Например это фрагменты код будет работать, пока все в том же блоке:

type 
    TExample = class 
    private 
     procedure HelloWorld; 
    public 
    ... 
    end; 

    implementation 

    function DoSomething(AExample: TExample); 
    begin 
     // Calling a private method here works 
     AExample.HelloWordl; 
    end; 
3

Да, вы можете получить доступ к подпрограмме, которая вложена в другой (родительской) подпрограмме, от внешнего мира. Хотя это несколько сложно. Я нашел это в Интернете.

Как пройти вложенную процедуру в качестве процедурного параметра (32 бит)

Delphi обычно не поддерживает прохождение вложенных подпрограмм в качестве процедурных параметров:

// This code does not compile: 
procedure testpass(p: tprocedure); 
begin 
    p; 
end; 
procedure calltestpass; 
procedure inner; 
begin 
    showmessage('hello'); 
end; 
begin 
    testpass(inner); 
end; 

Очевидное обходной путь должен пройти процедуру адрес и приведите его в тестовый комплект:

// This code compiles and runs OK 
procedure testpass(p: pointer); 
begin 
    tProcedure(p); 
end; 
procedure calltestpass; 
procedure inner; 
begin 
    showmessage('hello'); 
end; 
begin 
    testpass(@inner); 
end; 

Существует, однако, ловушка в a bove example - если «внутренняя» процедура ссылается на любую переменную, которая была нажата на стек, прежде чем «внутренняя» процедура была вызвана из testpass (параметры calltestpass - если были какие-либо или локальные переменные в callTestpass - если они были), ваш система вероятнее всего, происходит сбой:

// This code compiles OK but generates runtime exception (could even be 
// EMachineHangs :-)) 
procedure testpass(p: pointer); 
begin 
    tProcedure(p); 
end; 
procedure calltestpass; 
var msg: string; 
procedure inner; 
begin 
    msg := 'hello'; 
    showmessage(msg); 
end; 
begin 
    testpass(@inner); 
end; 

причина заключается в том, в простых словах, что расположение кадра стека было «разрушено» путем вызова testpass рутинными и «внутренним» процедура неправильно вычисляет параметры и локальные переменные местоположения (не вините Delphi, пожалуйста). Обходной путь заключается в настройке правильного контекста стека до «внутренний» вызывается из «testpass».

// This code compiles and runs OK 
{$O-} 
procedure testpass(p: pointer); 
var callersBP: longint; 
begin 
    asm // get caller's base pointer value at the very beginning 
    push dword ptr [ebp] 
    pop callersBP 
    end; 
// here we can have some other OP code 
    asm // pushes caller's base pointer value onto stack and calls tProcedure(p) 
    push CallersBP 
    Call p 
    Pop CallersBP 
    end; 
// here we can have some other OP code 
end; 
{$O+} 

procedure calltestpass; 
var msg: string; 
procedure inner; 
begin 
    msg := 'hello'; 
    showmessage(msg); 
end; 
begin 
    testpass(@inner); 
end; 

Пожалуйста, обратите внимание, что оптимизация отключена для процедуры проверки. Оптимизация обычно не очень хорошо обрабатывает смешанный код OP/ассемблера.