Qt复现pure virtual method called报错,与解决办法

现象

程序崩溃,报错:pure virtual method called,terminate called without an active exception,大意为调用了纯虚函数,程序中止。

原因分析

纯虚函数是没有函数体的虚函数。包含纯虚函数的类就叫抽象类。C++不允许抽象类实例化对象,正常情况下不会执行抽象类的纯虚函数。
虚函数通过函数表实现多态,在一些特殊情况下(不安全的代码写法)会发生纯虚函数的调用。

通常情况下在构造和析构的时候容易报"pure virtual method called"错误,这与基类和派生类的构造函数和析构函数的执行顺序有关。
构造函数执行顺序:
1、先初始化基类:将对象的虚函数指针指向基类虚函数表,初始化基类成员变量,调用基类构造函数;
2、再初始化派生类:将对象的虚函数表指针指向派生类虚函数表,初始化派生类成员变量,调用派生类构造函数。

析构顺序和构造顺序相反:
1、先析构派生类:对象的虚表指针指向的是派生类的虚函数表,调用派生类析构函数,执行派生类成员变量的析构;
2、再析构基类:将虚表指针指向基类虚函数表,调用基类析构函数,析构基类成员变量。

根据上面的流程,构造函数和析构函数执行过程中,都有一段时间对象的虚函数指针指向基类虚函数表,如果在构造或者析构没有完成的时候调用了该对象的虚函数,则是调用了基类的纯虚函数。这种情况一般发生在多线程调用,构造或析构在一个线程,虚函数调用在另一个线程。

解决思路

1、在调用对象的函数时,对象指针进行有效性判断(p==NULL);
2、不要再构造函数和析构函数中执行睡眠操作;
3、对对象指针加锁;
4、先停止线程,sleep,再执行析构,留一个时间隔离度,不要在析构函数里停止线程。

Qt复现pure virtual method called报错demo

运行后报错pure virtual method called,terminate called without an active exception,程序crash
mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include 
#include 

//基类
class Cheese{
public:
    Cheese(){};
    virtual ~Cheese(){QThread::msleep(200);};//基类析构函数执行了睡眠

    virtual void func() = 0;//纯虚函数
};
//派生类
class Cake : public Cheese{
public:
    Cake(){};
    virtual ~Cake(){};

    virtual void func(){};//虚函数
};

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private:
    Ui::MainWindow *ui;
    Cake *pCake;
    pthread_t ntid;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include 

void* thread_func(void* p)
{
    Cake *tCake = (Cake*)p;
    delete tCake;
    return NULL;
}

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    pCake = new Cake;
    pthread_create(&ntid,NULL,thread_func,pCake);//在子线程释放pCake
    QThread::msleep(20);//睡眠等待进入析构睡眠

    //多线程调用时,如果在别的线程执行了析构,当前线程还在继续调用pCake,则会报错
    //可以做pCake==NULL判断,避免普通的crash
    //但是如果基类的析构函数执行时间较长(比如在sleep),此时pCake!=NULL,还会执行下面的函数,此时就会pure virtual method called
    pCake->func();
}

MainWindow::~MainWindow()
{
    delete ui;
}

你可能感兴趣的:(C/C++,qt,c++,开发语言)