Виртуальный метод и этот указатель - PullRequest
1 голос
/ 01 октября 2010

Я только начинаю изучать C ++ и пытаюсь создать класс Thread, который имеет базовые функциональные возможности класса Java Thread.То, что я пытаюсь сделать, это создать класс, который вы подкласс, написать метод Run (который является чисто виртуальным в базовом классе), создать объект подкласса, вызвать метод start на нем, и у вас есть поток.

Проблема в том, что в том, как я использую C ++, диспетчеризация не выполняется правильно - как будто функция Run не виртуальная, вызывается метод Run базового класса.

Вот коддля заголовка

#ifndef _THREAD_H_
#define _THREAD_H_

#include <pthread.h>

class Thread {
 public:
  Thread();

  void Start();

  ~Thread();

 protected:
  virtual void Run() = 0;

 private:
  static void *RunWrapper(void *);

  pthread_t thread;
};

#endif

Реализация

#include "thread.h"

#include <pthread.h>

Thread::Thread() {
}

void Thread::Start() {
  pthread_create(&thread, NULL, Thread::RunWrapper, (void *) this);
}

void *Thread::RunWrapper(void *arg) {
  Thread *t = (Thread *) arg;
  t->Run();
  return arg;
}

Thread::~Thread() {
  pthread_join(thread, NULL);
}

И файл, который на самом деле пытается что-то сделать

#include <iostream>

#include "thread.h"

class MyThread : public Thread {
 protected:
  void Run() {
    std::cout << "The thread is runned" << std::endl;
  }
};

int main(void) {
  MyThread thread;
  thread.Start();
  return 0;
}

Ошибка, которую я получаю за последние 10Часы это:

pure virtual method called
terminate called without an active exception

Ответы [ 3 ]

5 голосов
/ 01 октября 2010

Проблема заключается в том, что ваш объект MyThread в main уничтожается, как только возвращается основная функция, что, вероятно, происходит до того, как новый поток действительно приступает к вызову своего метода Start.

Как часть процесса уничтожения, виртуальная таблица будет сброшена в виртуальную таблицу базового класса перед вызовом деструктора базового класса, поэтому при последующем запуске вызова RunWrapper она вызывает ошибку чисто виртуального метода. Вызов метода для уничтоженного объекта приводит к неопределенному поведению, поэтому может случиться что угодно; Такое поведение является случайностью того, как ваш компилятор C ++ реализует деструкторы и распределение стека.

0 голосов
/ 01 октября 2010

Проблема в том, что вы вызываете Start, который принадлежит классу Thread.Затем этот метод вызывает метод Run, который вызывает метод Run класса Thread.К сожалению, вы не можете вызвать переопределенный метод из базового класса.

0 голосов
/ 01 октября 2010

Не уверен, что непосредственно вызывает ошибку, но то, что вы делаете, плохо: ваш объект MyThread может выйти из области видимости, прежде чем ваш поток получит к нему доступ.Вполне возможно, что область действия исчезнет, ​​и указатель станет недействительным к тому времени, когда ваш поток начнет обрабатывать.

Попробуйте выделить свой объект в куче и посмотрите, работает ли он (а затем, предположив, что это работает, выясните, какосвободить объект, когда поток завершится).

О, и вы захотите в следующий раз выйти из приложения (вернувшись из основного), пока ваш поток также не будет завершен ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...