มาโคร Q_OBJECT ทำอะไร เหตุใดออบเจ็กต์ Qt ทั้งหมดจึงต้องการมาโครนี้


132

ฉันเพิ่งเริ่มใช้ Qt และสังเกตเห็นว่านิยามคลาสตัวอย่างทั้งหมดมีมาโครQ_OBJECTเป็นบรรทัดแรก จุดประสงค์ของมาโครตัวประมวลผลล่วงหน้านี้คืออะไร?


25
QT หมายถึง QuickTime และ Qt หมายถึงไลบรารี C ++ ที่เรียกว่า Qt
Bleadof

คำตอบ:


133

จากเอกสาร Qt :

Meta-Object Compiler คือโปรแกรมที่จัดการส่วนขยาย C ++ ของ Qt

เครื่องมือ moc อ่านไฟล์ส่วนหัว C ++ หากพบการประกาศคลาสตั้งแต่หนึ่งคลาสขึ้นไปที่มีมาโคร Q_OBJECT จะสร้างซอร์สไฟล์ C ++ ที่มีโค้ดเมตาอ็อบเจ็กต์สำหรับคลาสเหล่านั้น เหนือสิ่งอื่นใดรหัสเมตา - อ็อบเจ็กต์จำเป็นสำหรับสัญญาณและกลไกสล็อตข้อมูลชนิดรันไทม์และระบบคุณสมบัติไดนามิก


ทำไมฉันไม่จำเป็นต้องเขียนอย่างชัดเจนQ_OBJECT::connect()แต่เป็นเพียงแค่connect()?
mLstudent33

19

เพียงแค่บอกพรีคอมไพเลอร์ว่าคลาสนี้มีองค์ประกอบ gui และจำเป็นต้องรันผ่าน 'moc' คุณจะต้องเพิ่มสิ่งนี้ในคลาสที่ใช้กลไกสัญญาณ / สล็อตเท่านั้น
แต่จะถูกละเว้นอย่างเงียบ ๆ ในชั้นเรียนอื่น ๆ - เพียงแค่เพิ่มเวลาสร้าง


3
นอกจากนี้ยังเป็นเท็จที่คุณต้องการเฉพาะในคลาสที่ใช้กลไกสัญญาณ / สล็อต ไม่มีการQ_OBJECTแบ่งqobject_castและวิปัสสนา อาจนำไปสู่พฤติกรรมที่น่างงงวยดังนั้นจึงเป็นความคิดที่ไม่ดี
คืนสถานะ Monica

2
ไม่เป็นความจริงที่Q_OBJECTจะถูกเพิกเฉยในQObjectชั้นเรียนอื่น ๆ (ที่ไม่ใช่) ตามมาตรฐาน C ++ แนะนำพฤติกรรมที่ไม่ได้กำหนดโดยการประกาศฟังก์ชันและตัวแปรของสมาชิกหลายตัวที่ไม่เคยกำหนด นอกจากนี้ยังก่อให้เกิดเนมสเปซของชั้นเรียนของคุณด้วย - QObjectสมาชิกเฉพาะ เช่นเดียวอาจแบ่งชั้นที่ไม่เกี่ยวข้องที่เกิดขึ้นจะมีวิธีการที่เรียกว่าQ_OBJECT metaObject
คืนสถานะ Monica

2
นั่นผิด แม้ว่าคุณอาจต้องการจัดQ_OBJECTมาโครคลาส gui ส่วนใหญ่แต่ก็เหมาะสมอย่างยิ่งที่จะมีคลาสที่ไม่ใช่ gui กับมาโครเช่นเดียวกับคลาส gui ที่ไม่มีมาโคร มาโครมีประโยชน์ แต่ไม่ จำกัด หรือไม่จำเป็นสำหรับคลาส gui
pasbi

9

MOC (คอมไพเลอร์ออบเจ็กต์เมตา) แปลงมาโคร Q_OBJECT รวมไฟล์ส่วนหัวเป็นซอร์สโค้ดที่เทียบเท่า C ++ โดยทั่วไปจะควบคุมกลไกช่องสัญญาณและทำให้เข้าใจได้กับคอมไพเลอร์ C ++


2
นั่นเป็นเท็จ: Q_OBJECTมาโครถูกขยายโดยคอมไพเลอร์ไม่จำเป็นต้องใช้ moc สำหรับสิ่งนั้น moc ไม่ได้ทำอะไรกับมาโครเอง แต่สร้างคำจำกัดความของตัวแปรสมาชิกและวิธีการที่Q_OBJECTมาโครได้ประกาศไว้
คืนสถานะ Monica

5

1 จากเอกสาร Qt ของThe Meta-Object System

เครื่องมือ moc อ่านซอร์สไฟล์ C ++ หากพบการประกาศคลาสตั้งแต่หนึ่งคลาสขึ้นไปที่มีมาโคร Q_OBJECT จะสร้างซอร์สไฟล์ C ++ อื่นซึ่งมีโค้ดเมตาอ็อบเจ็กต์สำหรับแต่ละคลาสเหล่านั้น ซอร์สไฟล์ที่สร้างขึ้นนี้เป็น # include ในซอร์สไฟล์ของคลาสหรือโดยปกติแล้วจะรวบรวมและเชื่อมโยงกับการนำไปใช้งานของคลาส

2 จากเอกสาร Qt ของTHE Q_OBJECT

มาโคร Q_OBJECT ต้องปรากฏในส่วนไพรเวตของนิยามคลาสที่ประกาศสัญญาณและสล็อตของตัวเองหรือที่ใช้บริการอื่น ๆ ที่จัดเตรียมโดยระบบเมตาอ็อบเจ็กต์ของ Qt

3 จากเอกสาร Qt ของmoc

เครื่องมือ moc อ่านไฟล์ส่วนหัว C ++ หากพบการประกาศคลาสตั้งแต่หนึ่งคลาสขึ้นไปที่มีมาโคร Q_OBJECT จะสร้างซอร์สไฟล์ C ++ ที่มีโค้ดเมตาอ็อบเจ็กต์สำหรับคลาสเหล่านั้น เหนือสิ่งอื่นใดรหัสเมตา - อ็อบเจ็กต์จำเป็นสำหรับสัญญาณและกลไกสล็อตข้อมูลชนิดรันไทม์และระบบคุณสมบัติไดนามิก

4 จากเอกสาร Qt ของสัญญาณและสล็อต

แมโคร Q_OBJECT ถูกขยายโดยตัวประมวลผลล่วงหน้าเพื่อประกาศฟังก์ชันสมาชิกหลายอย่างที่ใช้งานโดย moc หากคุณได้รับข้อผิดพลาดของคอมไพเลอร์ตามบรรทัดของ "การอ้างอิงที่ไม่ได้กำหนดไปยัง vtable สำหรับ LcdNumber" คุณอาจลืมที่จะเรียกใช้ moc หรือรวมเอาต์พุต moc ไว้ในคำสั่งลิงก์


2

ใน gcc -Eคุณสามารถดูมาโครที่ขยายได้ นี่คือสิ่งที่Q_OBJECTขยายไปสู่ ​​gcc บน Linux โปรดทราบว่านี่อาจขึ้นอยู่กับแพลตฟอร์มและอาจเปลี่ยนแปลงได้ขึ้นอยู่กับเวอร์ชันของ QT คุณจะเห็นว่ามันไม่ใช่แค่แท็กสำหรับคอมไพเลอร์ 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

มาโคร Q_OBJECT ต้องปรากฏในส่วนไพรเวตของนิยามคลาสที่ประกาศสัญญาณและสล็อตของตัวเองหรือที่ใช้บริการอื่น ๆ ที่จัดเตรียมโดยระบบเมตาอ็อบเจ็กต์ของ Qt


1
นี้เป็นความเข้าใจผิดที่: แมโครต้องปรากฏในทุกชั้นเรียนที่มาจากQ_OBJECT QObjectโค้ดของคุณจะเสียอย่างละเอียดเมื่อไม่มีมาโครและเพียงเพราะมันเกิดขึ้นกับการคอมไพล์ไม่ได้ทำให้มันตกลง
คืนสถานะ Monica

@KubaOber คุณมีตัวอย่างโค้ดที่คอมไพล์ แต่ไม่ทำงานเมื่อQ_OBJECTมาโครหายไปหรือไม่?
คริส

2
หากคุณดูการใช้งานQ_OBJECTคุณจะพบว่ามันใช้ตัวระบุการเข้าถึง ดังนั้นไม่ว่าแมโครควรจะปรากฏในภายใต้private, protectedหรือpublicspecifiers ไม่เกี่ยวข้อง - เป็นเพียงการประชุมเพื่อวางไว้ที่หัวของชั้น
TrebledJ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.