Menggunakan emit vs memanggil sinyal seolah-olah itu adalah fungsi biasa di Qt

97

Katakanlah saya memiliki sinyal ini:

signals:
    void progressNotification(int progress);

Saya baru saja mengetahui tentang kata kunci emit di Qt. Sampai sekarang, saya biasa mengeksekusi sinyal hanya dengan memanggilnya seperti fungsi biasa. Jadi, alih-alih:

emit progressNotification(1000 * seconds);

Saya akan menulis:

progressNotification(1000 * seconds);

Memanggil mereka seperti itu sepertinya berhasil, dan semua slot yang terhubung akan dijalankan, jadi apakah menggunakan kata kunci emit menyebabkan perilaku yang berbeda, atau apakah itu hanya gula sintaksis?

sashoalm
sumber
17
+1 Tidak pernah tahu emittidak dibutuhkan. Anehnya, Anda mengetahui emitlama setelah memanggil sinyal secara langsung, karena sistem slot sinyal adalah salah satu hal pertama yang harus dipelajari tentang Qt.
Christian Rau

Jawaban:

88

emithanyalah gula sintaksis. Jika Anda melihat output pra-proses dari fungsi yang memancarkan sinyal, Anda akan melihat bahwa fungsi emittersebut hilang begitu saja.

"Ajaib" terjadi dalam kode yang dihasilkan untuk fungsi pemancar sinyal, yang dapat Anda lihat dengan memeriksa kode C ++ yang dihasilkan oleh moc.

Misalnya foosinyal tanpa parameter menghasilkan fungsi anggota ini:

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

Dan kode emit foo();tersebut diproses sebelumnya menjadi sederhanafoo();

emitdidefinisikan dalam Qt/qobjectdefs.h(bagaimanapun juga dalam ragam sumber terbuka dari sumber), seperti ini:

#ifndef QT_NO_EMIT
# define emit
#endif

(Define guard memungkinkan Anda untuk menggunakan Qt dengan framework lain yang memiliki nama yang bertabrakan melalui no_keywordsopsi konfigurasi QMake.)

Tikar
sumber
14
Apakah Anda tahu jika pernah ada implementasi (atau implementasi terencana) emityang benar-benar melakukan lebih dari tidak sama sekali? Saya menemukan bahwa memiliki 'gula sintaksis' dalam hal ini hanya membingungkan pemula (atau setidaknya saya ketika saya adalah pengguna Qt pemula) - tampaknya sesuatu yang ajaib atau penting terjadi dengan emitkata kunci pseudo, ketika tidak melakukan apa-apa pada semua - semua keajaiban terjadi dalam fungsi lama biasa yang mocmenciptakan ( mocadalah keajaiban untuk sinyal dan slot Qt). emitadalah dekorasi tak perlu yang tidak melakukan apa pun kecuali penting.
Michael Burr
12
Emit bukan "sekedar hiasan". emitmemberi tahu orang yang membaca panggilan bahwa keajaiban akan segera terjadi (yaitu ini akan memicu kode dalam objek yang mungkin tidak pernah didengar kelas ini, dan panggilan ini mungkin sinkron atau asinkron), yang pada dasarnya akan hilang total jika Anda menghilangkan kata kunci. Gunakan. Ini mendokumentasikan otomatis. "Pemula" harus membaca dokumen & tutorial, dan emitselalu ada (bagaimanapun juga di dokumen resmi). Menemukan bahwa Anda bisa memanggil fungsi itu harus terjadi setelah Anda "melihat cahaya" - Anda bukan pemula lagi pada saat itu.
Mat
19
Hmm, saya tidak yakin saya setuju dengan Anda tentang betapa berharganya emit'kata kunci' itu. Saya pikir saya lebih suka bahwa konvensi penamaan digunakan jika ada kebutuhan untuk memperjelas bahwa panggilan fungsi adalah sinyal.
Michael Burr
2
Yah, saya sangat tidak setuju dengan itu :) Memaksakan konvensi penamaan adalah sesuatu yang dapat Anda lakukan sendiri di proyek / tempat kerja Anda, Qt tidak mencegahnya. Qt tidak memaksa Anda untuk menggunakan "kata kunci", dan bahkan memungkinkan Anda untuk mematikannya jika bentrok dengan bagian lain dari kode Anda. Menurut pendapat saya, pendekatan kata kunci lebih baik - kompiler tidak dapat membantu Anda menegakkan kebijakan penamaan, tetapi akan menemukan kesalahan eja emit.
Mat
15
Untuk lebih jelasnya - saya tidak menganjurkan bahwa konvensi penamaan digunakan - hanya saja jika alasan emitpsuedo-kata kunci-komentar adalah untuk menjelaskan bahwa sinyal sedang dipanggil, maka konvensi penamaan dapat melakukan hal yang sama, tanpa misteri dan dengan manfaat serupa. Konvensi penamaan tidak dapat diberlakukan oleh Qt (sebenarnya, mocdapat menegakkannya - tetapi saya juga tidak menganjurkan itu), tetapi Qt tidak dapat memaksakan penggunaan emitkeduanya. Dan sementara Anda dapat 'mematikan' emitjika ada bentrokan nama, itu tidak banyak membantu jika Anda memiliki banyak file sumber yang menggunakannya (tidak perlu, untuk boot).
Michael Burr
2

Setelah 18 bulan ... Saya mulai dengan komentar di bawah jawaban @ Mat, dan segera kehabisan ruangan. Demikian jawabannya.

IMO emitbukanlah gula sintaksis atau kata kunci sederhana dalam arti itu

  1. Ini menghasilkan kode (seperti yang dijelaskan oleh @Mat di atas),
  2. Ini membantu connectmekanisme mengenali bahwa memang itu adalah signal, dan
  3. Itu membuat sinyal Anda menjadi bagian dari sistem yang "lebih besar", di mana sinyal dan respons (slot) dapat dijalankan secara sinkron atau asinkron, atau antri, tergantung di mana dan bagaimana sinyal itu dipancarkan. Ini adalah fitur yang sangat berguna dari sistem sinyal / slot.

Seluruh sistem sinyal / slot adalah idiom yang berbeda dari pemanggilan fungsi sederhana. Saya percaya itu berasal dari pola pengamat. Ada juga perbedaan besar antara a signaldan a slot: sinyal tidak harus diimplementasikan, sedangkan slot harus !

Anda sedang berjalan di jalan dan melihat sebuah rumah terbakar (sebuah sinyal). Anda menghubungi 911 ( hubungkan sinyal api dengan slot respons 911 ). Sinyalnya hanya dipancarkan , sedangkan slotnya diimplementasikan oleh pemadam kebakaran. Mungkin tidak tepat, tetapi Anda mengerti. Mari kita lihat contoh OP.

Beberapa objek backend mengetahui seberapa banyak kemajuan yang telah dibuat. Jadi itu hanya bisa emit progressNotification(...)memberi sinyal. Terserah kelas yang menampilkan bilah kemajuan yang sebenarnya, untuk mengambil sinyal ini dan menjalankannya. Tapi bagaimana pandangan terhubung ke sinyal ini? Selamat datang di sistem sinyal / slot Qt. Seseorang sekarang dapat membayangkan kelas manajer (biasanya semacam widget), yang terdiri dari objek tampilan dan objek komputasi data (keduanya QObjects), dapat berfungsi connect (m_myDataEngine, &DataEngine::progressNotification, m_myViewObj, &SimpleView::displayProgress).

Mari kita tidak membahas aspek desain kelas manajer, tetapi cukup untuk mengatakan bahwa di sinilah sistem sinyal / slot bersinar. Saya dapat fokus untuk merancang arsitektur yang sangat bersih untuk aplikasi saya. Tidak selalu, tetapi sering kali, saya menemukan bahwa saya hanya memancarkan sinyal tetapi menerapkan slot .

Jika dimungkinkan untuk menggunakan / memanggil metode sinyal tanpa pernah memancarkannya , maka itu berarti bahwa Anda tidak pernah membutuhkan fungsi itu sebagai sinyal sejak awal.

NameRakes
sumber
6
Tidak, emitmemang hanya makro kosong dan murni opsional. Tidak begitu juga dengan kata kunci signaldan slotyang diproses oleh moc. signaldigunakan untuk menyediakan fungsi implementasi, slotdigunakan untuk membuat entri objek meta sehingga ditemukan dengan SLOT(MySlot())makro atau di QML. emitadalah suggar sintaksis. Tidak ada yang akan mengeluh jika Anda menulis emit i++;(tetapi mungkin rekan kerja Anda) dan Anda masih tidak dapat terhubung i++.
derM
-5

Pilihan kedua akan menyiratkan bahwa Anda selalu tahu apa nama fungsi dan parameter fungsi dan bahwa objek yang Anda kirimi diketahui oleh fungsi tersebut. Kedua kasus tersebut tidak selalu benar, jadi itulah dua hal utama mengapa slot dan sinyal dibuat. "under-the-hood" sinyal dan mekanisme slot hanyalah sebuah meja dengan penunjuk ke setiap fungsi yang terhubung.

Juga, lihat pdf ini yang menjelaskan dengan sangat jelas sifat dari sinyal dan mekanisme slot: http://www.elpauer.org/stuff/a_deeper_look_at_signals_and_slots.pdf

Evert
sumber
Kedua cara tersebut membutuhkan pengetahuan nama sinyal dan parameternya - Anda memancarkannya, bagaimana Anda bisa memancarkan sesuatu yang tidak Anda ketahui? Keduanya memiliki semantik yang sama juga, keduanya identik.
Mat
1
Mungkin Anda mengacaukan panggilan sinyal dengan panggilan slot langsung? Tetapi saya harus mengakui bahwa saya juga bertanya-tanya tentang judul pertanyaan pada awalnya, karena saya tidak pernah tahu emititu hanya no-op. Tetapi bahkan dalam kasus ini membaca badan pertanyaan seharusnya sudah membereskan semuanya, jadi -1.
Christian Rau