2010-05-19 44 views
3

我知道的很多 - 子程序对其父程序/程序使用私人访问模式,对吗?从DPR或Delphi的其他功能/程序访问子功能/程序

有没有什么办法可以从“外部世界” - dpr或其他函数/程序中访问它们?

此外 - 哪种方式需要更多calcualtion和空间来编译文件?

例如:

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 2010-05-19 14:39:18

+0

它甚至不是私人的,它是内部的。它不存在于嵌入的“父”例程之外。 – 2010-05-19 17:25:25

回答

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; 

不管能见度,对类的方法,可以通过RTTI采用Delphi 2010调用。我已经详细说明了如何在this article中做到这一点。

如果您处于同一个单元类中,则可以通过任何其他代码访问其他代码,除非它们被标记为Strict Private。 This Questionaccepted answer中有更多的细节和很好的示例代码。

如果你有两个不同的单位,你可以使用Protected Method Hack来访问受保护的方法。详情请参见this article

2

没有,有没有办法做到你的要求。功能xyz功能可调用只有通过封装blablabla功能。在该功能之外,xyz不在范围内,因此无法命名它。如果C++允许嵌套函数,那么就没有办法引用它,就像无法从当前翻译单元之外引用具有静态链接的函数一样。

如果您需要从blablabla功能以外呼叫xyz,然后将xyz移到外面。如果您需要从当前设备外部调用它,则需要在设备的接口部分声明该功能。然后,将该单元添加到外部代码的uses子句中,您可以从任何地方拨打xyz,即使是DPR文件。

如果xyz指变量或blablabla函数的参数,那么你就需要在将它们作为参数,因为xyz将不再有权访问它们,否则。

访问说明符的概念在这里并不真正相关,因为我们不是在谈论类。单位有接口实施部分,这是不是一个真正的类一样公共私人部分。

7

嵌套过程/函数 - 在另一个过程或函数中声明的那些是一种特殊类型,因为它们可以访问它们所嵌套过程的堆栈(并因此可以访问参数/局部变量)。因此,Delphi范围规则,则无法在“父”程序之外访问它们。只有在需要利用其特殊功能时才使用它们。 AFAIK德尔福/帕斯卡尔是少数有这种功能的语言之一。从编译器的角度来看,调用有一些额外的代码来允许访问父堆栈帧IIRC。 C++中的AFAIK“friend”类/函数是不同的 - 它们是类访问方法,而在您的示例中,您使用的是简单的过程/函数。 在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

是的,你可以访问一个子程序,这是嵌套在其他(父)子例程,从外面的世界。虽然有点棘手。我在网上找到了这个howto。

如何通过嵌套例程作为程序参数(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; 

显而易见的解决方法是通过程序地址并在testpass内部进行类型转换:

// 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; 

但是, e上面的例子 - 如果“内部”例程引用了从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”内调用“inner”之前设置正确的堆栈上下文。

// 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; 

请注意,对于testpass例程,优化被关闭 - 优化通常不能很好地处理混合的OP /汇编代码。