Название: [РЕШЕНО] Непонятное поведение виртуальных методов
Отправлено: vunder от Октябрь 12, 2010, 09:38
Объявил следующий класс: C++ (Qt) class UnpProtocol : public QThread { Q_OBJECT private slots: void onThreadStop(); protected: bool m_connected; virtual void unpDisconnect(); virtual void unpConnect(); void run(); protected slots: virtual void onTcpConnected(); virtual void onTcpDisconnected(); virtual void onTcpError(QAbstractSocket::SocketError); public: UnpProtocol(); ~UnpProtocol(); signals: void needRegistration(); void registrationResult(bool); }; UnpProtocol::UnpProtocol() : QThread(0) { this->moveToThread(this); } UnpProtocol::~UnpProtocol() { exit(); wait(); } void UnpProtocol::run() { connect(fSocket, SIGNAL(connected()), this, SLOT(onTcpConnected())); connect(fSocket, SIGNAL(disconnected()), this, SLOT(onTcpDisconnected())); connect(fSocket, SIGNAL(readyRead()), this, SLOT(onTcpReadyRead())); connect(fSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onTcpError(QAbstractSocket::SocketError))); connect(this, SIGNAL(finished()), SLOT(onThreadStop())); unpConnect(); // unpDisconnect(); exec(); } void UnpProtocol::unpConnect() { m_connected = false; } void UnpProtocol::unpDisconnect() { m_connected = false; } void UnpProtocol::onTcpDisconnected() { #ifdef QT_DEBUG qDebug() << "Disconnet form address"; #endif } void UnpProtocol::onTcpConnected() { #ifdef QT_DEBUG qDebug() << "Connected to address"; #endif } void UnpProtocol::onTcpError(QAbstractSocket::SocketError err) { #ifdef QT_DEBUG QString strError = "Error: " + (err == QAbstractSocket::HostNotFoundError ? "The host was not found." : err == QAbstractSocket::RemoteHostClosedError ? "The remote host is closed." : err == QAbstractSocket::ConnectionRefusedError ? "The connection was refused." : QString("other error - %1").arg(fSocket->errorString()) ); qDebug() << strError; #endif m_connected = false; } void UnpProtocol::onThreadStop() { if (m_connected) unpDisconnect(); }
Объявил потомка C++ (Qt) class UnpClientProtocol: public UnpProtocol { Q_OBJECT private: bool selfDisconnect; int timerId; protected: void unpConnect(); void unpDisconnect(); void run(); void timerEvent(QTimerEvent* event); protected slots: void onTcpConnected(); void onTcpDisconnected(); void onTcpError(QAbstractSocket::SocketError); public: UnpClientProtocol(); }; UnpClientProtocol::UnpClientProtocol() : UnpProtocol(), selfDisconnect(false), timerId(0) { } void UnpClientProtocol::run() { fSocket = new QTcpSocket(this); UnpProtocol::run(); if (timerId) killTimer(timerId); } void UnpClientProtocol::timerEvent(QTimerEvent *event) { UnpProtocol::timerEvent(event); if (event->timerId() == timerId) { #ifdef QT_DEBUG qDebug() << "Reconnect timer event! Trying to reconnect..."; #endif killTimer(timerId); timerId = 0; unpConnect(); } } void UnpClientProtocol::unpConnect() { selfDisconnect = false; UnpProtocol::unpConnect(); fSocket->connectToHost(hostAddress, portNumber); } void UnpClientProtocol::unpDisconnect() { UnpProtocol::unpDisconnect(); selfDisconnect = true; fSocket->disconnectFromHost(); fSocket->waitForDisconnected(); } void UnpClientProtocol::onTcpConnected() { UnpProtocol::onTcpConnected(); emit needRegistration(); } void UnpClientProtocol::onTcpDisconnected() { UnpProtocol::onTcpDisconnected(); if (!selfDisconnect) { m_connected = false; emit registrationResult(m_connected); if (timerId) killTimer(timerId); #ifdef QT_DEBUG qDebug() << "Starting reconnect timer"; #endif timerId = startTimer(5000); } } void UnpClientProtocol::onTcpError(QAbstractSocket::SocketError err) { UnpProtocol::onTcpError(err); emit registrationResult(m_connected); if (timerId) killTimer(timerId); #ifdef QT_DEBUG qDebug() << "Starting reconnect timer"; #endif timerId = startTimer(5000); }
Проблема в том, что при срабатывании слота UnpProtocol::onThreadStop() и вызове внутри метода unpDisconnect() вызывается метод UnpProtocol::unpDisconnect(), а не UnpClientProtocol::unpDisconnect(). Причем, если вызвать unpDisconnect() из метода UnpProtocol::run() (я закомментировал строку), то нормально срабатывает UnpClientProtocol::unpDisconnect(). Подскажите, где ошибся!!!
Название: Re: Непонятное поведение виртуальных методов
Отправлено: Amigo_sa от Октябрь 12, 2010, 10:36
Покажите плиз код, объект какого типа создается?
Название: Re: Непонятное поведение виртуальных методов
Отправлено: vunder от Октябрь 12, 2010, 10:42
Создается экземпляр UnpClientProtocol C++ (Qt) class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); private: UnpClientProtocol *fUnp; }; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), dlgSettings(0) { fUnp = new UnpClientProtocol(); fUnp->start(); } MainWindow::~MainWindow() { delete fUnp; }
Название: Re: Непонятное поведение виртуальных методов
Отправлено: vunder от Октябрь 12, 2010, 10:43
Нашел решение. Экземпляр класса UnpClientProtocol удалялся в деструкторе главной формы, причем я сразу вызывал delete Unp, а сам поток останавливался в деструкторе UnpProtocol (см. код выше) Если перед удалением поставить вызов Unp->quit() Unp->wait(), то все отрабатывает нормально. Сложилось впечатление, что когда управление передается деструктору UnpProtocol, то в этот момент данные о его наследнике уже удалены из памяти, поэтому невозможно перейти на метод наследника UnpClientProtocol::unpDisconnect(), а можно только на код UnpProtocol::unpDisconnect() Таким образом, получилось такое: C++ (Qt) MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), dlgSettings(0) { fUnp = new UnpClientProtocol(); fUnp->start(); } MainWindow::~MainWindow() { fUnp->quit(); fUnp->wait(); delete fUnp; }
|