Tôi nghĩ tôi nên thêm phần sau đây.
Có another linked question - và có a very good article có thể được xem là mở rộng khá chi tiết cho số answer; here is this article again, với cú pháp mã được cải thiện (mặc dù vẫn chưa hoàn hảo).
Dưới đây là kể lại của tôi ngắn của nó, mà bạn có thể dễ bị sai lầm)
Về cơ bản khi chúng ta chèn Q_OBJECT
vĩ mô trong định nghĩa lớp của chúng tôi, tiền xử lý mở rộng nó vào một tuyên bố QMetaObject
dụ tĩnh, một trong đó sẽ được chia sẻ bởi tất cả các trường của cùng một lớp:
class ClassName : public QObject // our class definition
{
static const QMetaObject staticMetaObject; // <--= Q_OBJECT results to this
// ... signal and slots definitions, other stuff ...
}
dụ này, đến lượt nó, về khởi tạo sẽ lưu trữ các chữ ký ("methodname(argtype1,argtype2)"
) của các tín hiệu và các khe, những gì sẽ cho phép để thực hiện các indexOfMethod()
cuộc gọi, mà trả về, tốt, chỉ số phương pháp bằng cách đó là chuỗi chữ ký:
struct Q_CORE_EXPORT QMetaObject
{
// ... skip ...
int indexOfMethod(const char *method) const;
// ... skip ...
static void activate(QObject *sender, int signal_index, void **argv);
// ... skip ...
struct { // private data
const QMetaObject *superdata; // links to the parent class, I guess
const char *stringdata; // basically, "string1\0string2\0..." that contains signatures and other names
const uint *data; // the indices for the strings in stringdata and other stuff (e.g. flags)
// skip
} d;
};
Bây giờ khi moc
tạo ra các tập tin moc_headername.cpp
cho lớp tiêu đề Qt headername.h
, nó đặt có các chuỗi chữ ký và các dữ liệu khác đó là cần thiết cho khởi tạo chính xác cấu trúc d
và sau đó viết mã khởi tạo cho singleton staticMetaObject
bằng cách sử dụng dữ liệu này.
Một điều quan trọng nó là thế hệ của mã cho phương pháp qt_metacall()
của đối tượng, mà sẽ đưa id phương pháp của một đối tượng và một mảng của con trỏ đối số và gọi phương pháp này qua một chặng đường dài switch
như thế này:
int ClassName::qt_metacall(..., int _id, void **_args)
{
// ... skip ...
switch (_id) {
case 0: signalOrSlotMethod1(_args[1], _args[2]); break; // for a method with two args
case 1: signalOrSlotMethod2(_args[1]); break; // for a method with a single argument
// ... etc ...
}
// ... skip ...
}
cuối cùng, đối với mỗi tín hiệu moc
tạo ra một thực hiện, trong đó có một cuộc gọi QMetaObject::activate()
:
void ClassName::signalName(argtype1 arg1, argtype2 arg2, /* ... */)
{
void *_args[] = { 0, // this entry stands for the return value
&arg1, // actually, there's a (void*) type conversion
&arg2, // in the C++ style
// ...
};
QMetaObject::activate(this,
&staticMetaObject,
0, /* this is the signal index in the qt_metacall() map, I suppose */
_args
);
}
cuối cùng, cuộc gọi connect()
dịch các STRI ng chữ ký phương thức để id số nguyên của họ (những cái được sử dụng bởi qt_metacall()
) và duy trì một danh sách các kết nối tín hiệu để khe; khi tín hiệu được phát ra, mã activate()
đi qua danh sách này và gọi đối tượng thích hợp là "khe" qua phương thức qt_metacall()
của chúng.
Để tổng hợp, trường hợp QMetaObject
tĩnh lưu trữ "siêu thông tin" (phương thức chữ ký chuỗi vv), phương thức qt_metacall()
được tạo ra cung cấp "bảng phương thức" cho phép bất kỳ tín hiệu/khe nào được gọi bằng chỉ mục, tín hiệu triển khai được tạo ra bởi moc
sử dụng các chỉ mục này qua activate()
và cuối cùng là connect()
thực hiện công việc duy trì danh sách các bản đồ chỉ mục tín hiệu đến vị trí.
* Lưu ý: có một biến chứng của lược đồ này được sử dụng cho trường hợp chúng tôi muốn gửi tín hiệu giữa các luồng khác nhau (tôi nghi ngờ rằng phải xem mã blocking_activate()
), nhưng tôi hy vọng ý tưởng chung vẫn giữ nguyên)
Đây là sự hiểu biết rất thô của tôi về bài viết liên quan, trong đó một cách dễ dàng có thể sai, vì vậy tôi khuyên bạn nên đi và đọc nó trực tiếp)
PS. Khi tôi muốn cải thiện sự hiểu biết của mình về việc triển khai Qt - hãy cho tôi biết về bất kỳ sự mâu thuẫn nào trong việc kể lại của tôi!
Kể từ khác (trước đó) câu trả lời của tôi đã bị xóa bởi một số biên tập viên sốt sắng, tôi sẽ nối các văn bản ở đây (tôi đang thiếu vài chi tiết mà là không đưa vào bài Pavel Shved, và tôi nghi ngờ người đó người đã xóa câu trả lời được chăm sóc.)
@Pavel Shved:
Tôi khá chắc chắn rằng đâu đó trong tiêu đề Qt tồn tại một dòng:
#define emit
Chỉ để xác nhận: tìm thấy nó trong mã Qt cũ Tìm kiếm bằng Google Code. Rất có khả năng nó vẫn còn đó); con đường vị trí tìm thấy là:
ftp://ftp.slackware-brasil.com.br> slackware-7.1> contrib> kde-1.90> qt-2.1.1.tgz> usr> lib> qt-2.1.1> src> kernel> qobjectdefs.h
Một liên kết complementory: http://lists.trolltech.com/qt-interest/2007-05/thread00691-0.html - xem câu trả lời bởi Andreas Pakulat
Và đây là một phần của câu trả lời: Qt question: How do signals and slots work?
đẹp câu hỏi. Xem thêm: http://stackoverflow.com/questions/1413777/how-boost-implements-signals-and-slots – elcuco