Sử dụng phát ra so với gọi một tín hiệu như thể đó là một hàm thông thường trong Qt


97

Giả sử tôi có tín hiệu này:

signals:
    void progressNotification(int progress);

Tôi chỉ mới biết gần đây về từ khóa phát ra trong Qt. Cho đến bây giờ, tôi thường thực hiện các tín hiệu bằng cách chỉ gọi chúng như một hàm thông thường. Vì vậy, thay vì:

emit progressNotification(1000 * seconds);

Tôi sẽ viết:

progressNotification(1000 * seconds);

Việc gọi chúng như vậy dường như hoạt động và tất cả các khe cắm được kết nối sẽ thực thi, vậy việc sử dụng từ khóa phát ra có gây ra một hành vi khác hay chỉ là đường cú pháp?


17
+1 Chưa bao giờ biết emitlà không cần thiết. Tuy nhiên, thật lạ là bạn đã học được emitrất lâu sau khi gọi tín hiệu trực tiếp, vì hệ thống khe cắm tín hiệu là một trong những điều đầu tiên được tìm hiểu về Qt.
Christian Rau

Câu trả lời:


88

emitchỉ là đường cú pháp. Nếu bạn nhìn vào đầu ra được xử lý trước của hàm phát ra tín hiệu, bạn sẽ thấy emitnó biến mất.

"Điều kỳ diệu" xảy ra trong mã được tạo cho chức năng phát tín hiệu, bạn có thể xem xét bằng cách kiểm tra mã C ++ được tạo bởi moc.

Ví dụ, một footín hiệu không có tham số tạo ra hàm thành viên này:

void W::foo()
{
    QMetaObject::activate(this, &staticMetaObject, 0, 0);
}

Và mã emit foo();được xử lý trước để đơn giảnfoo();

emitđược định nghĩa trong Qt/qobjectdefs.h(dù sao trong hương vị mã nguồn mở của nguồn), như sau:

#ifndef QT_NO_EMIT
# define emit
#endif

(Bảo vệ xác định là cho phép bạn sử dụng Qt với các khuôn khổ khác có tên xung đột thông qua no_keywordstùy chọn cấu hình QMake.)


14
Bạn có biết nếu có bao giờ một triển khai (hoặc một kế hoạch thực hiện) emitthực sự không làm gì hơn không? Tôi thấy rằng việc có 'đường cú pháp' trong trường hợp này chỉ gây nhầm lẫn cho người mới bắt đầu (hoặc ít nhất là tôi khi tôi là người dùng Qt mới bắt đầu) - có vẻ như điều gì đó kỳ diệu hoặc quan trọng đang xảy ra với emittừ khóa giả, khi nó không làm gì cả tất cả - tất cả điều kỳ diệu xảy ra trong một hàm cũ thông thường moctạo ra ( moclà điều kỳ diệu đối với tín hiệu Qt và khe cắm). emitlà trang trí không cần thiết không làm gì nhưng có vẻ quan trọng.
Michael Burr

12
Phát ra không phải là "chỉ trang trí". emitnói với người đọc cuộc gọi rằng điều kỳ diệu sắp xảy ra (tức là điều này sẽ kích hoạt mã trong các đối tượng mà lớp này có thể chưa bao giờ nghe đến và các lệnh gọi này có thể đồng bộ hoặc không đồng bộ), về cơ bản sẽ hoàn toàn bị mất nếu bạn bỏ qua từ khóa. Sử dụng nó. Nó tự động ghi lại tài liệu. "Người mới sử dụng" nên đọc tài liệu & hướng dẫn và emitluôn ở đó (dù sao cũng có trong tài liệu chính thức). Việc khám phá ra rằng bạn chỉ có thể gọi hàm sẽ xảy ra sau khi bạn "nhìn thấy ánh sáng" - lúc đó bạn không phải là người mới nữa.
Mat

19
Rất tiếc, tôi không chắc mình đồng ý với bạn về giá trị của emit'từ khóa'. Tôi nghĩ rằng tôi sẽ thích sử dụng quy ước đặt tên hơn nếu cần phải làm rõ rằng một lệnh gọi hàm là một tín hiệu.
Michael Burr

2
Chà, tôi hoàn toàn không đồng ý với điều đó :) Bắt buộc quy ước đặt tên là điều bạn có thể tự làm trong các dự án / nơi làm việc của mình, Qt không ngăn cản điều đó. Qt không buộc bạn sử dụng "từ khóa" và thậm chí còn cho phép bạn tắt nó đi nếu nó xung đột với các phần khác trong mã của bạn. Theo tôi, cách tiếp cận từ khóa tốt hơn - trình biên dịch không thể giúp bạn thực thi các chính sách đặt tên, nhưng nó sẽ bắt lỗi chính tả emit.
Mat

15
Nói rõ hơn - tôi không ủng hộ việc sử dụng quy ước đặt tên - chỉ là nếu lý do cho một emitbình luận từ khóa psuedo là để làm rõ rằng một tín hiệu đang được gọi, thì quy ước đặt tên có thể làm tương tự, không có bí ẩn và với những lợi ích tương tự. Quy ước đặt tên không thể được thực thi bởi Qt (thực sự, moccó thể thực thi nó - nhưng tôi cũng không ủng hộ điều đó), nhưng Qt không thể thực thi việc sử dụng emitcả hai. Và trong khi bạn có thể 'tắt' emitnếu có xung đột tên, điều đó không giúp ích nhiều nếu bạn có một loạt các tệp nguồn đang sử dụng nó (không cần thiết, để khởi động).
Michael Burr

2

Sau 18 tháng ... tôi bắt đầu nhận xét dưới câu trả lời của @ Mat, và nhanh chóng hết chỗ. Như vậy câu trả lời.

IMO emitkhông phải là đường cú pháp cũng không phải là một từ khóa đơn giản theo nghĩa

  1. Nó tạo mã (như được giải thích bởi @Mat ở trên),
  2. Nó giúp connectcơ chế nhận ra rằng nó thực sự là một signal, và
  3. Nó làm cho tín hiệu của bạn trở thành một phần của hệ thống "lớn hơn", nơi các tín hiệu và phản hồi (khe cắm) có thể được thực thi đồng bộ hoặc không đồng bộ hoặc xếp hàng đợi, tùy thuộc vào vị trí và cách tín hiệu được phát ra. Đây là một tính năng cực kỳ hữu ích của hệ thống tín hiệu / khe cắm.

Toàn bộ hệ thống tín hiệu / khe cắm là một thành ngữ khác với một cách gọi hàm đơn giản. Tôi tin rằng nó bắt nguồn từ mẫu người quan sát. Ngoài ra còn có một sự khác biệt lớn giữa a signalvà a slot: một tín hiệu không cần phải được triển khai, trong khi phải có một khe cắm !

Bạn đang đi bộ xuống phố và thấy một ngôi nhà đang bốc cháy (một tín hiệu). Bạn quay số 911 ( kết nối tín hiệu báo cháy với khe phản hồi 911 ). Tín hiệu chỉ được phát ra , trong khi khe cắm đã được thực hiện bởi cơ quan cứu hỏa. Có thể không chính xác, nhưng bạn có ý tưởng. Hãy xem ví dụ về OP.

Đối tượng phụ trợ nào đó biết tiến trình đã được thực hiện. Vì vậy, nó có thể chỉ đơn giản là emit progressNotification(...)báo hiệu. Tùy thuộc vào lớp hiển thị thanh tiến trình thực tế, nhận tín hiệu này và thực thi trên nó. Nhưng làm thế nào để khung nhìn kết nối với tín hiệu này? Chào mừng đến với hệ thống tín hiệu / khe cắm của Qt. Bây giờ người ta có thể quan niệm về một lớp người quản lý (thường là một widget của các loại), bao gồm một đối tượng xem và một đối tượng tính toán dữ liệu (cả hai đều là QObjects), có thể hoạt động connect (m_myDataEngine, &DataEngine::progressNotification, m_myViewObj, &SimpleView::displayProgress).

Chúng ta đừng đi sâu vào các khía cạnh thiết kế của lớp người quản lý, nhưng đủ để nói rằng đây là nơi hệ thống khe cắm / tín hiệu tỏa sáng. Tôi có thể tập trung vào việc thiết kế một kiến ​​trúc rất rõ ràng cho ứng dụng của mình. Không phải lúc nào cũng vậy, nhưng đôi khi, tôi thấy rằng tôi chỉ phát ra tín hiệu nhưng thực hiện các khe cắm .

Nếu có thể sử dụng / gọi một phương thức tín hiệu mà không bao giờ phát ra nó , thì điều đó nhất thiết ngụ ý rằng ngay từ đầu bạn chưa bao giờ cần đến chức năng đó như một tín hiệu .


6
Không, emitthực sự chỉ là một macro trống và hoàn toàn là tùy chọn. Không phải như vậy là các từ khóa signalslotđược xử lý bởi moc. signalđược sử dụng để cung cấp việc triển khai chức năng, slotđược sử dụng để tạo mục nhập đối tượng meta để nó được tìm thấy với SLOT(MySlot())macro hoặc trong QML. emitlà gợi ý cú pháp. Sẽ không có gì phàn nàn nếu bạn viết thư emit i++;(nhưng có thể là đồng nghiệp của bạn) và bạn vẫn không thể kết nối với i++.
derM

-5

Tùy chọn thứ hai sẽ ngụ ý rằng bạn luôn biết tên hàm và các tham số của hàm là gì và đối tượng mà bạn gửi nó đến được biết bởi hàm cụ thể đó. Hai trường hợp đó không phải lúc nào cũng đúng, vì vậy đó là hai điều chính tại sao khe cắm và tín hiệu được tạo ra. "ẩn" cơ chế tín hiệu và khe cắm chỉ là một bảng với các con trỏ đến mọi chức năng được kết nối.

Ngoài ra, hãy xem bản pdf này giải thích rất rõ ràng bản chất của cơ chế tín hiệu và vị trí: http://www.elpauer.org/stuff/a_deeper_look_at_signals_and_slots.pdf


Cả hai cách đều yêu cầu phải biết tên tín hiệu và các thông số của nó - bạn đang phát ra nó, làm sao bạn có thể phát ra thứ mà bạn không biết? Cả hai đều có cùng ngữ nghĩa, chúng giống hệt nhau.
Mat

1
Có thể bạn đang làm rối một cuộc gọi tín hiệu với một cuộc gọi trực tiếp? Nhưng tôi phải thừa nhận rằng ban đầu tôi cũng băn khoăn về tiêu đề câu hỏi, vì tôi chưa bao giờ biết emitnó chỉ là một câu trả lời không cần chọn. Nhưng ngay cả trong trường hợp này, việc đọc nội dung câu hỏi lẽ ra phải làm rõ mọi thứ, vì vậy -1.
Christian Rau
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.