Tôi mới bắt đầu sử dụng Qt và nhận thấy rằng tất cả các định nghĩa lớp mẫu có macro Q_OBJECT
là dòng đầu tiên. Mục đích của macro tiền xử lý này là gì?
Tôi mới bắt đầu sử dụng Qt và nhận thấy rằng tất cả các định nghĩa lớp mẫu có macro Q_OBJECT
là dòng đầu tiên. Mục đích của macro tiền xử lý này là gì?
Câu trả lời:
Từ tài liệu Qt :
Trình biên dịch Meta-Object, moc, là chương trình xử lý các phần mở rộng C ++ của Qt.
Công cụ moc đọc tệp tiêu đề C ++. Nếu nó tìm thấy một hoặc nhiều khai báo lớp có chứa macro Q_OB DỰ ÁN, nó sẽ tạo ra một tệp nguồn C ++ chứa mã đối tượng meta cho các lớp đó. Trong số những thứ khác, mã đối tượng meta được yêu cầu cho cơ chế tín hiệu và khe, thông tin loại thời gian chạy và hệ thống thuộc tính động.
Q_OBJECT::connect()
mà chỉ là connect()
?
Nó chỉ đơn giản nói với trình biên dịch trước rằng lớp này có các phần tử gui và cần được chạy qua 'moc', bạn chỉ cần thêm phần này vào các lớp sử dụng cơ chế tín hiệu / khe cắm.
Nhưng nó sẽ lặng lẽ bị bỏ qua trong bất kỳ lớp nào khác - nó chỉ thêm vào thời gian xây dựng.
Q_OBJECT
phá vỡ qobject_cast
và nội tâm. Nó có thể dẫn đến một số hành vi bối rối, vì vậy đó là một ý tưởng tồi.
Q_OBJECT
sẽ bị "lặng lẽ" bỏ qua trong bất kỳ lớp nào khác (không phải QObject
). Theo tiêu chuẩn C ++, nó giới thiệu hành vi không xác định bằng cách khai báo một số hàm thành viên và các biến không bao giờ được xác định. Nó cũng gây ô nhiễm không gian tên của lớp bạn với QObject
các thành viên cụ thể. Ví dụ, một lớp Q_OBJECT
có thể phá vỡ một lớp không liên quan có thể chứa một phương thức được gọi metaObject
.
Q_OBJECT
macro, nhưng thật tuyệt vời khi có các lớp không gui với macro, cũng như các lớp gui mà không có macro. Macro là hữu ích, nhưng không giới hạn và cũng không bắt buộc đối với các lớp gui.
MOC (trình biên dịch đối tượng meta) chuyển đổi các tệp tiêu đề bao gồm macro Q_OB DỰ ÁN thành mã nguồn tương đương C ++. Về cơ bản, nó điều khiển cơ chế khe tín hiệu và làm cho trình biên dịch C ++ dễ hiểu
Q_OBJECT
macro được mở rộng bởi trình biên dịch, moc không cần thiết cho điều đó. Các moc không làm bất cứ điều gì với chính macro, nhưng nó tạo ra các định nghĩa về các biến thành viên và các phương thức mà Q_OBJECT
macro đã khai báo .
1 Từ tài liệu Qt của Hệ thống Meta-Object
Công cụ moc đọc tệp nguồn C ++. Nếu nó tìm thấy một hoặc nhiều khai báo lớp có chứa macro Q_OB DỰ ÁN, nó sẽ tạo ra một tệp nguồn C ++ khác chứa mã đối tượng meta cho mỗi lớp đó. Tệp nguồn được tạo này là # bao gồm trong tệp nguồn của lớp hoặc, thông thường hơn, được biên dịch và liên kết với việc triển khai của lớp.
2 Từ tài liệu Qt của THE Q_OB DỰ ÁN
Macro Q_OB Project phải xuất hiện trong phần riêng của định nghĩa lớp khai báo các tín hiệu và vị trí của chính nó hoặc sử dụng các dịch vụ khác được cung cấp bởi hệ thống đối tượng meta của Qt.
3 Từ tài liệu Qt của moc
Công cụ moc đọc tệp tiêu đề C ++. Nếu nó tìm thấy một hoặc nhiều khai báo lớp có chứa macro Q_OB DỰ ÁN, nó sẽ tạo ra một tệp nguồn C ++ chứa mã đối tượng meta cho các lớp đó. Trong số những thứ khác, mã đối tượng meta được yêu cầu cho cơ chế tín hiệu và khe, thông tin loại thời gian chạy và hệ thống thuộc tính động.
4 Từ tài liệu Qt về Tín hiệu và Slots
Macro Q_OB DỰ ÁN được bộ tiền xử lý mở rộng để khai báo một số hàm thành viên được thực hiện bởi moc; nếu bạn gặp lỗi trình biên dịch dọc theo dòng "tham chiếu không xác định đến vtable cho LcdNumber", có lẽ bạn đã quên chạy moc hoặc đưa đầu ra moc vào lệnh liên kết.
Trong gcc với -E
bạn có thể thấy các macro mở rộng. Đây là những gì Q_OBJECT
mở rộng trên gcc trên Linux. Xin lưu ý, điều này có thể phụ thuộc vào nền tảng và nó có thể thay đổi tùy thuộc vào phiên bản của QT. Bạn có thể thấy nó không chỉ là một thẻ cho trình biên dịch moc.
# 11 "mainwindow.hh"
#pragma GCC diagnostic push
# 11 "mainwindow.hh"
# 11 "mainwindow.hh"
#pragma GCC diagnostic ignored "-Wsuggest-override"
# 11 "mainwindow.hh"
static const QMetaObject staticMetaObject; virtual const QMetaObject *metaObject() const; virtual void *qt_metacast(const char *); virtual int qt_metacall(QMetaObject::Call, int, void **); static inline QString tr(const char *s, cons
t char *c = nullptr, int n = -1) { return staticMetaObject.tr(s, c, n); } __attribute__ ((__deprecated__)) static inline QString trUtf8(const char *s, const char *c = nullptr, int n = -1) { return staticMetaObject.tr(s, c, n); } private:
# 11 "mainwindow.hh"
#pragma GCC diagnostic ignored "-Wattributes"
# 11 "mainwindow.hh"
__attribute__((visibility("hidden"))) static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **);
# 11 "mainwindow.hh"
#pragma GCC diagnostic pop
# 11 "mainwindow.hh"
struct QPrivateSignal {};
Macro Q_OB Project phải xuất hiện trong phần riêng của định nghĩa lớp khai báo các tín hiệu và vị trí của chính nó hoặc sử dụng các dịch vụ khác được cung cấp bởi hệ thống đối tượng meta của Qt.
Q_OBJECT
Macro phải xuất hiện trong mọi lớp xuất phát từ QObject
. Mã của bạn sẽ bị phá vỡ một cách tinh tế khi macro vắng mặt và chỉ vì nó xảy ra để biên dịch không làm cho nó ổn.
Q_OBJECT
thiếu macro không?
Q_OBJECT
, bạn sẽ thấy rằng nó sử dụng các chỉ định truy cập. Vì vậy, cho dù vĩ mô sẽ xuất hiện trong dưới private
, protected
hoặc public
specifiers là không thích hợp - nó chỉ là ước để đặt nó ở phần đầu của lớp.