2010-05-19 43 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 /彙編代碼。