程序崩溃,报错:pure virtual method called,terminate called without an active exception,大意为调用了纯虚函数,程序中止。
原因分析纯虚函数是没有函数体的虚函数。包含纯虚函数的类就叫抽象类。C++不允许抽象类实例化对象,正常情况下不会执行抽象类的纯虚函数。
虚函数通过函数表实现多态,在一些特殊情况下(不安全的代码写法)会发生纯虚函数的调用。
通常情况下在构造和析构的时候容易报"pure virtual method called"错误,这与基类和派生类的构造函数和析构函数的执行顺序有关。
构造函数执行顺序:
1、先初始化基类:将对象的虚函数指针指向基类虚函数表,初始化基类成员变量,调用基类构造函数;
2、再初始化派生类:将对象的虚函数表指针指向派生类虚函数表,初始化派生类成员变量,调用派生类构造函数。
析构顺序和构造顺序相反:
1、先析构派生类:对象的虚表指针指向的是派生类的虚函数表,调用派生类析构函数,执行派生类成员变量的析构;
2、再析构基类:将虚表指针指向基类虚函数表,调用基类析构函数,析构基类成员变量。
根据上面的流程,构造函数和析构函数执行过程中,都有一段时间对象的虚函数指针指向基类虚函数表,如果在构造或者析构没有完成的时候调用了该对象的虚函数,则是调用了基类的纯虚函数。这种情况一般发生在多线程调用,构造或析构在一个线程,虚函数调用在另一个线程。
解决思路1、在调用对象的函数时,对象指针进行有效性判断(p==NULL);
2、不要再构造函数和析构函数中执行睡眠操作;
3、对对象指针加锁。
运行后报错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" #includevoid* 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; }



