2013-08-22 44 views
6

Có hợp lệ để gọiKết nối tín hiệu với các khe có ít thông số được phép trong Qt?

QObject::connect(a, SIGNAL(somesig(someparam)), b, SLOT(someslot())); 

không có thông số? Nó dường như làm việc (không có ngoại lệ thời gian chạy ném) nhưng tôi không thể tìm thấy một tài liệu tham khảo trong các tài liệu. Tất cả tôi tìm thấy là điều này là có thể nếu someslot có một tham số mặc định. Nó hợp lệ trong trường hợp này. Nhưng phương pháp someslot của tôi không có cùng tham số được đặt làm mặc định (không có tham số ở đây trong ví dụ).

Vì vậy, có vẻ như có thể truyền tín hiệu đến các vị trí có ít thông số hơn?

Trả lời

9

Vâng, được rồi. Có một câu ngắn về nó trong tài liệu Signals & Slots:

[...] Chữ ký của tín hiệu phải khớp với chữ ký của khe nhận. (Trong thực tế, một khe cắm có thể có một chữ ký ngắn hơn so với các tín hiệu mà nó nhận được vì nó có thể bỏ qua đối số thêm.) [...]

Thậm chí còn có một ví dụ như vậy tiếp tục xuống trang mà đối số mặc định là giải thích.

+0

Điều này cũng tuân thủ bất kỳ tiêu chuẩn C++ nào hay là tính năng được đảm bảo hoạt động trên mỗi Qt? Ít nhất trong đồng bằng C, điều này dẫn đến UB qua ISO/IEC 9899: TC2 §6.5.2.2p6. – Kamajii

+0

@Kamajii: cuộc gọi vị trí không phải là cuộc gọi hàm trực tiếp. Không có UB, Qt sẽ chăm sóc gọi hàm một cách chính xác. – Mat

+0

Tất nhiên là những lời gọi khe chỉ là các cuộc gọi thông thường (các kết nối + -queued, vv). Khi phát xạ tín hiệu cuối cùng đạt tới thành viên qt_static_metacall' được tạo tự động, vấn đề chính phát sinh. – Kamajii

1

Về mặt chuẩn C++, giải pháp Qt cũng hoạt động.

phát ra một tín hiệu được thực hiện bằng cách gọi một phương pháp:

emit someSignal(3.14); 

Từ khóa emit thực sự giải quyết cho một sản phẩm nào #define, vì vậy dòng trên chỉ gọi phương thức someSignal với các đối số cho trước. Phương pháp này có thể đã được khai báo bên trong một lớp -derived QObject như vậy:

class SomeObject: public QObject { 
    Q_OBJECT 
public slots: 
    void firstSlot() { /* implementation */ } 
    void secondSlot(double) { /* implementation */ } 

signals: 
    void someSignal(double); /* no implementation here */ 
}; 

này nên dường như quen thuộc với bạn, tuy nhiên bạn có thể đã tự hỏi nơi thực hiện thực tế của các tín hiệu của bạn đến từ đâu. Như bạn có thể đoán, đây là nơi trình biên dịch đối tượng meta Qt của (MOC) đá trong Đối với mỗi phương pháp tuyên bố trong phần signals nó cung cấp trong nguồn tạo ra nó một thực hiện rằng khoảng trông như thế này:.

void SomeObject::someSignal(double _t1) 
{ 
    void *_a[] = { Q_NULLPTR, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) }; 
    QMetaObject::activate(this, &staticMetaObject, 1, _a); 
} 

Phần thú vị là vector void *_a[] được làm đầy với các con trỏ tới các đối số được chuyển tới tín hiệu. Không có gì đặc biệt ở đây.

Vectơ đối số được chuyển đến QMetaObject::activate, lần lượt thực hiện một số kiểm tra an toàn luồng và các dịch vụ vệ sinh khác và sau đó bắt đầu gọi các vị trí đã được kết nối với tín hiệu, nếu có. Khi các kết nối tín hiệu tới khe được giải quyết trong thời gian chạy (cách mà connect() hoạt động), cần một chút trợ giúp từ MOC một lần nữa. Đặc biệt, Bộ Xây dựng cũng tạo ra một qt_static_metacall() thực hiện lớp học của bạn:

void SomeObject::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) 
{ 
    if (_c == QMetaObject::InvokeMetaMethod) { 
     SomeObject *_t = static_cast<SomeObject *>(_o); 
     Q_UNUSED(_t) 
     switch (_id) { 
     case 0: _t->firstSlot(); break; 
     case 1: _t->secondSlot((*reinterpret_cast< double(*)>(_a[1]))); break; 
     default: ; 
     } 
    } /* some more magic */ 
} 

Như bạn có thể thấy, phương pháp này chứa bên kia để giải quyết các vector void *_a[] từ trước đến một lời gọi hàm. Ngoài ra, bạn có thể thấy rằng không có danh sách đối số variadic (sử dụng dấu ba chấm, ...) hoặc các thủ thuật có vấn đề khác có liên quan.

Vì vậy, để khai sáng câu hỏi gốc: Khi nào, ví dụ:someSignal(double) được kết nối với secondSlot(double) khớp với chữ ký của tín hiệu, cuộc gọi sẽ chuyển thành case 1 trong qt_static_metacall và nó chỉ chuyển đối số như mong đợi.

Khi kết nối tín hiệu với firstSlot() có ít đối số hơn tín hiệu, cuộc gọi sẽ giải quyết thành case 0firstSlot() được gọi mà không có đối số. Đối số đã được chuyển cho tín hiệu đơn giản là không bị ảnh hưởng trong vector void *_a[] của nó.