2015-09-16 13 views
5

Tại sao mã này không dẫn đến lỗi trình biên dịch? Tôi đã có thể mong đợi lỗi ví dụ 'gọi mơ hồ đến "CallMe"'. Đây có phải là lỗi trong trình biên dịch hoặc bằng ngôn ngữ không? Điều này có thể làm việc xung quanh bằng cách sử dụng tên đơn vị và một dấu chấm ở phía trước của cuộc gọi hàm nhưng điều này không bảo vệ mã người dùng và mã thư viện chống lại xung đột tên. Bạn nghĩ rằng mã của bạn đã làm một cái gì đó nhưng nó đã làm một cái gì đó khác và đó là xấu.Tại sao không gọi một hàm có chữ ký giống hệt nhau trong các đơn vị khác nhau dẫn đến lỗi trình biên dịch?

uses 
    Unit2, Unit3; 

{$R *.lfm} 
{ TForm1 } 
procedure TForm1.Button1Click(Sender: TObject); 
begin 
    ShowMessage(IntToStr(CallMe(5))); 
end; 

unit Unit2; 
{$mode objfpc}{$H+} 
interface 
uses 
    Classes, SysUtils; 
function CallMe(A: Integer) : Integer; 
implementation 
function CallMe(A: Integer) : Integer; 
begin 
    Result := A * 2; 
end; 
end. 

unit Unit3; 
{$mode objfpc}{$H+} 
interface 
uses 
    Classes, SysUtils; 
function CallMe(A: Integer) : Integer; 
implementation 
function CallMe(A: Integer) : Integer; 
begin 
    Result := A * -1; 
end; 
end. 
+5

Đây là theo thiết kế: Nó gọi trình biên dịch đã thấy cuối cùng trong quá trình biên dịch. Nếu bạn muốn gọi cho người khác, hãy thêm tên đơn vị vào trước theo sau là dấu chấm cho tên. – MartynA

+0

Cảm ơn. Tôi muốn biết động lực đằng sau thiết kế này. Điều này tạo cơ hội cho các lỗi. Giả sử đơn vị ban đầu sử dụng CallMe từ Unit2 thì lập trình B đến và thêm unit3 vì anh ta cần một số chức năng từ đó và không biết rằng anh ta vô tình thay thế CallMe bằng một thứ khác (tưởng tượng một đơn vị dài có nhiều mã). Nó biên dịch và chạy. Không cảnh báo không có lỗi. Tôi thà có một lỗi biên dịch hơn là một vấn đề thời gian chạy và tôi không muốn AVeryLongLibraryName.FunctionName cuộc gọi và để xem mọi cuộc gọi trong mỗi đơn vị bao gồm cho một cuộc gọi mơ hồ. –

+1

Bất kỳ ngôn ngữ lập trình nào cũng tạo cơ hội cho các lỗi. Toàn bộ điều là: bạn phải biết mình đang làm gì. Có những công cụ bên ngoài cung cấp cho bạn gợi ý về những trường hợp đó. –

Trả lời

13

Từ documentation:

Nếu hai đơn vị khai báo một biến, hằng số, chủng loại, quy trình, hoặc chức năng có cùng tên, trình biên dịch sử dụng một từ đơn vị niêm yết cuối cùng trong khoản sử dụng . (Để truy cập số nhận dạng từ đơn vị khác, bạn sẽ phải thêm một bộ định danh: UnitName.Identifier.)

+0

Tôi hiểu.Tôi phải nói điều này rất đáng ngạc nhiên và trong hành vi nguy hiểm của tôi. Một thư viện được thêm vào sau cho một dự án có một hàm có cùng chữ ký như trong mã cũ và mã cũ đã bắt đầu sử dụng hàm mới vì đơn vị mới được thêm vào cuối cùng trong mệnh đề sử dụng và hàm mới có lỗi và hoạt động khác gây ra rắc rối. Bạn có biết điều này có thể được biến thành một lỗi biên dịch bởi tùy chọn để điều này không xảy ra một lần nữa do tai nạn? –

+0

Tôi đã sống với hành vi này kể từ TP4 ngày, và không bao giờ thực sự có bất kỳ vấn đề với các cuộc đụng độ tên. Không có tùy chọn gợi ý/cảnh báo/lỗi để cho biết tình trạng này. Sự hiểu biết mã có thể được trợ giúp mặc dù, cho thấy đơn vị chức năng thuộc về. –

+0

@ user2304430: Không có cách nào biến nó thành lỗi, vì đó không phải là lỗi. –

2

Như đã nói, theo trình thiết kế, trình biên dịch tải biểu tượng từ các đơn vị sử dụng phương pháp tiếp cận dựa trên ngăn xếp và phân tích cú pháp thông qua ngăn xếp từ lần tải cuối cùng đến lần tải đầu tiên để tìm kiếm một biểu tượng. Trạng thái tiền xử lý được hợp nhất trực tiếp vào trạng thái toàn cầu.

Quá tải đơn vị chéo là một ngoại lệ. Nếu bạn đánh dấu cả hai hàm với quá tải ; chỉ thị, bạn nhận được một lỗi (bla là tên của hàm trong các thử nghiệm)

[dcc32 Error] test.dpr: E2251 Ambiguous overloaded call to 'bla' 
    Unit1.pas(8): Related method: procedure bla; 
    Unit2.pas(8): Related method: procedure bla; 

nếu bạn có hai chữ ký khác nhau, nó sẽ chọn phù hợp tốt nhất.

quá tải chéo là một tính năng mới hơn, nhưng tôi không nhớ chính xác thời điểm nào. Tôi đoán là D2006.

Các vấn đề liên quan