Russian Qt Forum
Май 02, 2024, 12:58 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: [РЕШЕНО] Непонятное поведение виртуальных методов  (Прочитано 3299 раз)
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().
Подскажите, где ошибся!!!
« Последнее редактирование: Октябрь 12, 2010, 21:19 от vunder » Записан
Amigo_sa
Гость
« Ответ #1 : Октябрь 12, 2010, 10:36 »

Покажите плиз код, объект какого типа создается?
Записан
vunder
Гость
« Ответ #2 : Октябрь 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;
}
 
Записан
vunder
Гость
« Ответ #3 : Октябрь 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;
}
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.133 секунд. Запросов: 20.