Sự khác nhau giữa tin nhắn và phương thức?


13

Trong Mục tiêu C, bạn có khái niệm gửi tin nhắn đến các đối tượng khác, và, điều này rất giống với cách gọi phương thức trong các ngôn ngữ như C # và Java.

Nhưng chính xác những khác biệt tinh tế là gì? Làm thế nào tôi nên nghĩ về nhắn tin khi nghĩ về mã của tôi?

Lưu ý: Chỉ cần một chút nền tảng ở đây, tôi là nhà phát triển C # / Java đang cố gắng hiểu một số khái niệm về Objective C.


2
Vì chúng là tất cả các ngôn ngữ khác nhau, sự khác biệt không tinh tế. Chúng là những ngôn ngữ khác nhau. "Khi nghĩ về mã của tôi"? Mã gì? Khi nghĩ về Java hoặc C #, bạn không nghĩ về các thông báo. Bạn nghĩ về phương pháp. Bạn có thể làm rõ làm thế nào các ngôn ngữ không liên quan với các khái niệm không liên quan có thể có sự khác biệt "tinh tế"?
S.Lott

1
Vui lòng hỏi bạn câu hỏi tại stackoverflow.com
Amir Rezaei

1
Câu hỏi này có thực sự có trên StackOverflow không? Đó là một câu hỏi về các khái niệm lập trình không phải là vấn đề về một số mã tôi đã có. Có lẽ tôi đã sai, tôi không biết - ranh giới đang bị xóa nhòa ...
Vidar

1
@Vidar, câu hỏi không chủ quan. Bạn đang tìm kiếm một định nghĩa sách giáo khoa. Lập trình viên là nhiều hơn cho ý kiến, kinh nghiệm và câu hỏi chủ quan.
Stephen Furlani

1
OK - có cách nào để người điều hành chuyển câu hỏi này sang StackOverflow không?
Vidar

Câu trả lời:


10

Một thông điệp là tên của một bộ chọn và các tham số cho bộ chọn đó.

Một bộ chọn là một biểu tượng.

Phương thức là một đoạn mã trong một lớp được xác định bởi bộ chọn.

Nói cách khác, [foo bar: baz]nói "gửi tin nhắn được gọi @selector(bar:)với tham số bazđến đối tượng foo. Bạn có thể gửi tin nhắn đó đến nhiều đối tượng khác nhau.

Ngược lại, phương thức bar: cho một Foocó thể trông giống như

-(int)bar:(int)n {
  return n + 1;
}

nhưng FooTwocó vẻ như

-(int)bar:(int)n {
  return n + 2;
}

(Tôi hy vọng tôi có cú pháp đúng; đã một thời gian kể từ lần cuối tôi chạm vào Objective-C.)

Khi bạn gửi tin nhắn, nhân Objective-C sẽ gửi tin nhắn đến fooquyết định xem nó có hiểu tin nhắn hay không. Nó quyết định điều này dựa trên việc nó có thể tìm ra một phương thức được xác định bởi bộ chọn đó hay không.

Hai phương thức có cùng tên và một thông điệp.

Cũng có thể một đối tượng chỉ cần chuyển tiếp một tin nhắn cụ thể (hoặc bộ tin nhắn) đến một đối tượng khác để xử lý. Trong trường hợp này, bạn gửi tin nhắn đến đối tượng proxy này, không có phương thức nào khớp với tin nhắn đó và proxy chuyển tiếp tin nhắn đến đối tượng được bọc của nó.


vì vậy ... một thông báo là khi bạn gọi một dispinterface (a.invoke selector, args) và một phương thức là khi bạn gọi một giao diện (a.methodName)? Điều đó sẽ không tạo ra java, JavaScript, tất cả các ngôn ngữ động đều có thông báo vì mọi thứ xảy ra thông qua giao diện kép thay vì nhảy trực tiếp và bù vào các bước nhảy vtable)?
Dmitry

3

Từ quan điểm lý thuyết thuần túy, không có sự khác biệt nào giữa hai điều này - đã có một số bằng chứng chính thức cho thấy hai điều này hoàn toàn tương đương, và có thể được thực hiện hoàn toàn về mặt khác.

Từ quan điểm lý thuyết ít hơn một chút, có một điểm khác biệt có thể xảy ra: trong một triển khai điển hình, bảng chức năng ảo được phân bổ tĩnh và nội dung của mỗi vtable được cố định tại thời điểm biên dịch. Ngược lại, việc tra cứu thư thường được thực hiện với một số loại đối tượng giống như bản đồ, thường là động, nghĩa là bạn có thể sửa đổi nó khi chạy. Điều này làm cho việc thêm một phản hồi mới vào một thông điệp trong một lớp hiện có tương đối dễ dàng. Thật không may, trong hầu hết các trường hợp, điều này vẫn chủ yếu là lý thuyết. Đầu tiên, về cơ bản bạn đang xử lý mã tự sửa đổi, điều mà hầu hết mọi người quyết định là một ý tưởng khá tệ từ lâuthời gian trước. Thứ hai, để làm cho nó rất có ý nghĩa, bạn cần rất nhiều khả năng biên dịch mã mới vào lớp hiện có để trả lời tin nhắn mới mà bạn hỗ trợ. Không có điều đó, về tất cả những gì bạn đạt được là khả năng tự động thêm một tên mới cho một phương thức hiện có.

Như ngụ ý ở cuối đoạn trước, từ quan điểm thực tế thực tế, có rất ít sự khác biệt giữa cả hai. Chúng chỉ đơn giản là hai (rất ít) cách khác nhau để hỗ trợ ràng buộc muộn. Mặc dù việc tra cứu dựa trên tin nhắn thường chậm hơn một chút, nhưng sẽ rất bất thường khi sự khác biệt thực sự quan trọng. Đối với hầu hết các mục đích thực tế, chúng chỉ là hai cách khác nhau để thực hiện cùng một điều.


2
Bạn có tài liệu tham khảo cho thấy bằng chứng? Tôi muốn xem qua. Có một sự khác biệt lớn giữa việc gọi phương thức của Java và gửi tin nhắn của Smalltalk, không chỉ vì ràng buộc muộn mà còn vì sự tách rời của người gửi và người nhận: bạn không thể biết liệu người nhận tin nhắn có xử lý nó hay chuyển tiếp tin nhắn trên, ví dụ.
Frank Shearar

1

Trong Objective-C, các thông điệp bị ràng buộc muộn. Đó là chúng được giải quyết trong thời gian chạy. C # hỗ trợ một cấu trúc tương tự thông qua từ khóa Động, cũng tuyên bố một đối tượng cũng bị ràng buộc muộn.


0

Thông thường các cuộc gọi phương thức được giải quyết tại thời gian biên dịch (trừ khi bạn sử dụng sự phản chiếu trong Java), trong khi các thông báo trong Mục tiêu C được gửi đi trong thời gian chạy.


2
Nếu các cuộc gọi phương thức được giải quyết là thời gian biên dịch, thì bạn không sử dụng OOP, bạn đang sử dụng đường cú pháp cho các hàm quá tải lấy structtham số đầu tiên. Bindung muộn là một phần thiết yếu của đa hình và do đó của OOP.

2
Đúng. Nhưng bạn vẫn chỉ có thể viết mã một cuộc gọi phương thức chống lại một cái gì đó (bằng Java) được biết đến nhiều vào thời gian biên dịch. Gọi MyObject.foo () sẽ báo lỗi nếu MyObject hoặc MyInterface không có phương thức foo () được xác định. ObjC sẽ cho phép gửi cho bạn một tin nhắn 'foo' để phản đối MyObject - và nếu MyObject không có 'foo', điều này sẽ đánh bom vào thời gian chạy.
Heiko Rupp

Tôi nghĩ Objective C là một ngôn ngữ được biên dịch?
Vidar

1
Điều đó không được thực hiện đối với ràng buộc sớm / muộn (gõ động so với kiểu chữ cấu trúc - trong ví dụ của bạn, các lệnh gọi phương thức được kiểm tra tại compXLime nhưng không nhất thiết phải được gửi đi ). @Vidar: Nó là, nhưng nó thêm phép thuật cho các tính năng động. Bạn cũng có thể biên dịch Python.

@Vidar: Đây không phải là vấn đề được biên dịch so với diễn giải, mà là tĩnh so với động. Trong các ngôn ngữ OOP tĩnh như Java, trình biên dịch sẽ kiểm tra để đảm bảo rằng một lớp định nghĩa một phương thức trong giai đoạn biên dịch. Trong một ngôn ngữ được gõ động như Objective-C, các thông điệp được truyền trong thời gian chạy.
mipadi

-1

Các thông điệp được xử lý bởi kernel hoặc bằng chính ngôn ngữ (ví dụ ObjC, có một mã lắp ráp rất nhỏ thực hiện nó).

Ví dụ, trong nhân linux, các thông báo được thực hiện với các cuộc gọi / chức năng của hệ thống: bạn có thể tìm thấy chúng nếu bạn tìm kiếm về lập trình hệ thống unix.

Sự khác biệt cốt lõi giữa một cuộc gọi phương thức và một thông báo là:

  • một cuộc gọi phương thức chỉ xảy ra trong mã của bạn: trong ASM, nó được dịch bởi một PUSH của các đối số được truyền.

  • một thông điệp kernel chủ yếu là một cái gì đó được gửi đến kernel được theo dõi và gửi lại cho một tiến trình nhất định. Tôi có thể nhầm chúng với các đường ống, nhưng bất cứ điều gì: biết rằng đã có một cơ chế cho phép bạn chạy một số chương trình cùng một lúc và cho phép giao tiếp cùng một lúc. Tất nhiên, đừng hy vọng rằng điều này sẽ hoạt động theo cách tương tự trên windows hoặc HĐH khác.


Đây không phải là "thông điệp truyền đi" vì nó áp dụng cho các ngôn ngữ lập trình.
mipadi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.