Macro Q_OB DỰ ÁN làm gì? Tại sao tất cả các đối tượng Qt cần macro này?


131

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_OBJECTlà dòng đầu tiên. Mục đích của macro tiền xử lý này là gì?


25
QT đề cập đến QuickTime và Qt đề cập đến thư viện C ++ có tên Qt.
Bleadof

Câu trả lời:


132

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.


Tại sao tôi không cần phải tự viết Q_OBJECT::connect()mà chỉ là connect()?
mLstudent33

19

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.


3
Cũng sai khi bạn chỉ cần nó trên các lớp sử dụng cơ chế tín hiệu / khe cắm. Sự vắng mặt của Q_OBJECTphá vỡ qobject_castvà 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.
Phục hồi lại

2
Điều đó không đúng sự thật Q_OBJECTsẽ 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 QObjectcác thành viên cụ thể. Ví dụ, một lớp Q_OBJECTcó 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.
Phục hồi lại

2
Sai rồi. Mặc dù bạn có thể muốn trang bị cho hầu hết các lớp gui với Q_OBJECTmacro, 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.
pasbi

9

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


2
Điều đó là sai: Q_OBJECTmacro đượ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_OBJECTmacro đã khai báo .
Phục hồi lại

5

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.


2

Trong gcc với -Ebạn có thể thấy các macro mở rộng. Đây là những gì Q_OBJECTmở 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 {};

0

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.


1
Điều này là sai lệch: Q_OBJECTMacro 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.
Phục hồi lại

@KubaOber bạn có một ví dụ về mã biên dịch nhưng không hoạt động khi Q_OBJECTthiếu macro không?
Chris

2
Nếu bạn nhìn vào việc thực hiện 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, protectedhoặc publicspecifiers là không thích hợp - nó chỉ là ước để đặt nó ở phần đầu của lớp.
TrebledJ
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.