2012-04-05 36 views
12

Tôi đang tạo một lớp cơ sở trừu tượng và nghĩ rằng tôi có thể muốn có tín hiệu ảo thuần túy. Nhưng khi tôi biên soạn tôi nhận được một cảnh báo cho các tín hiệu ảo tinh khiết Tôi đã xác định:Có hợp lệ để xác định tín hiệu ảo thuần túy trong C++/Qt không?

../FILE1.h:27: Warning: Signals cannot be declared virtual 
../FILE1.h:28: Warning: Signals cannot be declared virtual 

Có hợp lệ để xác định một tín hiệu ảo tinh khiết trong C++/Qt? Có hợp lệ để xác định tín hiệu ảo không?

Qt's signal and slot documentation page cho biết bạn có thể xác định các khe ảo nhưng không nói về tín hiệu. Tôi không thể tìm thấy thông tin tốt về tín hiệu ảo thuần túy.

+0

[Trên ghi chú không liên quan Qt cho phép các khe ảo thuần túy ... nhưng không đề cập đến các tín hiệu ảo thuần túy.] (Http://stackoverflow.com/questions/2998216/does-qt-support-virtual-pure-slots) –

+1

Tại sao bạn nghĩ bạn muốn tạo tín hiệu ảo? – Chris

+0

Một cách tiếp cận khác, sử dụng CRTP và một lớp cơ sở chung được đưa ra [trong câu trả lời này] (http://stackoverflow.com/a/32124726/1329652). Nó cho phép dễ dàng bao thanh toán ra khỏi mã phổ biến cho nhiều lớp học có nguồn gốc từ QObject', ngay cả khi chúng xuất phát từ các lớp cơ sở khác nhau (chúng không cần phải lấy trực tiếp từ 'QObject'). –

Trả lời

7
  • Tín hiệu không bao giờ có triển khai [1] (tức là bạn xác định tín hiệu trong tệp .h và sau đó không có triển khai trong .cpp).
  • Mục đích chính của việc khai báo hàm thuần ảo là buộc lớp kế thừa cung cấp triển khai.

Căn cứ vào hai câu nói trên đây là suy nghĩ của tôi:

Tín hiệu không có một thực hiện nhưng tuyên bố nó tinh khiết ảo sẽ đòi hỏi các lớp kế thừa để cung cấp một thực hiện ... mà trực tiếp mâu thuẫn với "tín hiệu don không có triển khai ". Nó giống như yêu cầu ai đó ở hai nơi cùng một lúc, điều đó là không thể.

Vì vậy, trong kết luận, có vẻ như tuyên bố tín hiệu "thuần ảo" "phải là lỗi và do đó không hợp lệ.


Trong trường hợp của một lớp cơ sở trừu tượng ở đây là những gì tôi nghĩ là đúng:

Khi một tuyên bố chức năng chỉ "ảo" nó vẫn cung cấp cho các cảnh báo. Để tránh bất kỳ cảnh báo nào, tôi nghĩ giải pháp không đủ điều kiện tín hiệu với bất kỳ "ảo" hoặc "ảo ảo" và sau đó lớp kế thừa sẽ không khai báo bất kỳ tín hiệu nào nhưng vẫn có thể phát ra các tín hiệu được xác định trong lớp cơ sở.

[1] khi tôi nói rằng "tín hiệu không bao giờ có triển khai", nghĩa là người triển khai lớp không cung cấp triển khai. Tôi hiểu rằng hậu trường của Qt cung cấp một triển khai thực hiện trong moc_FILE1.cpp.

2

Tôi nghĩ đơn giản là không có điểm nào trong việc có tín hiệu ảo (thuần). vĩ mô signals được cung cấp cho Qt chỉ đơn giản là mở rộng đến protected, vì vậy tất cả các tín hiệu bạn đang tuyên bố thực sự là khai báo các phương thức được bảo vệ. Mã được tạo bởi moc sẽ cung cấp việc triển khai các chức năng đó.

0

có một giải pháp để tạo chức năng ảo thuần túy sẽ kết nối khe được cho để báo hiệu hoặc ngược lại. ví dụ .:

class IBaseInterface 
{ 
    public: 
    virtual bool connectToSignal1(QObject* pReceiver, const char* pszSlot, bool bConnect) const = 0; 
}; 

class CDerived : public QObject, public IBaseInterface 
{ 
    Q_OBJECT 
    public: 
    virtual bool connectToSignal1(QObject* pReceiver, const char* pszSlot, bool bConnect) const; 
    signals: 
    void signal1(const QString& msg); 
}; 

bool CDerived::connectToSignal1(QObject* pReceiver, const char* pszSlot, bool bConnect) const 
{ 
if(bConnect) 
    return connect(this, SIGNAL(signal1(QString)), pReciever, pszSlot); 
return disconnect(this, SIGNAL(signal1(QString)), pReciever, pszSlot); 
} 

hơn nữa trong khách hàng một mã có thể gõ:

class CSomeClass : public QObject 
{ 
    Q_OBJECT 
protected /*or public, or private*/ slots: 
    void someSlot(const QString& msg); 
}; 
void CSomeClass::somefunction() 
{ 
    IBaseInterface* p = new CDerived; 
    if (!p->connectToSignal1(this, SLOT(someSlot(QString)), true)) 
    QMessageBox::warning(this, tr("Warning"), tr("Cannot connect ...."), QMessageBox::Ok); 
} 
+0

[This] (http://stackoverflow.com/a/18113601/1329652) là một giải pháp tốt hơn nhiều, mặc dù. –

4

Các cảnh báo được báo cáo bởi moc, không phải bởi ++ biên dịch C, và nó là hợp lệ ngoại trừ trong trường hợp cụ thể của giao diện trừu tượng.

Việc sử dụng hợp lệ duy nhất cho tín hiệu ảo là khi khai báo giao diện trừu tượng không lấy được từ QObject, dưới dạng detailed in this excellent answer. Không có gì sai với cách tiếp cận đó. Mộc cố gắng hữu ích, vì trong hầu hết các trường hợp, tín hiệu ảo là một sai lầm.

Ngay cả khi đó, cách giải quyết đơn giản để không nhận cảnh báo là bỏ qua từ khóa signals: trong giao diện. Đó là hoàn toàn không cần thiết, vì giao diện không bắt nguồn từ QObject và do đó không nên được xử lý bởi moc tại tất cả:

// https://github.com/KubaO/stackoverflown/tree/master/questions/virtual-slot-10029130 
#include <QtCore> 

class IDogInterface { 
public: 
    // no signals: section since it's not a QObject! 
    virtual void barks() = 0; // a signal 
}; 

class ADog : public QObject, public IDogInterface { 
    Q_OBJECT 
public: 
    Q_SIGNAL void barks() override; // implementation is generated by moc 
}; 

class Monitor : public QObject { 
    Q_OBJECT 
    int m_count{}; 
    Q_SLOT void onBark() { m_count++; } 
public: 
    int count() const { return m_count; } 
    void monitorBarks(IDogInterface * dog) { 
     QObject * dogObject = dynamic_cast<QObject*>(dog); 
     if (dogObject) { 
     connect(dogObject, SIGNAL(barks()), SLOT(onBark())); 
     } else { 
     qWarning() << "cannot monitor barking on dog instance" << (void*)dog; 
     } 
    } 
}; 

int main() { 
    ADog dog; 
    Monitor monitor; 
    monitor.monitorBarks(&dog); 
    emit dog.barks(); 
    Q_ASSERT(monitor.count() == 1); 
} 
#include "main.moc" 
0

Hai kịch bản mà một tín hiệu ảo có ý nghĩa:

  1. Các nguồn gốc lớp có thể muốn chặn có chọn lọc việc gửi tín hiệu bằng cách bỏ qua việc triển khai lớp cơ sở.
  2. Lớp dẫn xuất có thể muốn sử dụng nó làm cơ chế sự kiện và phản ứng với tín hiệu trước hoặc sau khi gửi cho người nghe.

Cả hai trường hợp cũng có thể được xử lý theo các cách ít OOP khác.

Các vấn đề liên quan