pure virtual method called错误简记

错误1

错误源码

class Base {
public:
    virtual void foo() = 0;
    Base() { call_foo();  }
    void call_foo() { foo(); }
};

class Derived : Base {
    void foo() {  }
};

int main() {
Derived d;
}

运行结果

pure virtual method called
terminate called without an active exception
Aborted

说明

1)如果在Base()构造函数中,直接调用foo()虚函数,会编译报错;
2)如果foo不为纯虚函数,不会报错;

原因

1)虚函数表指针vptr初始化时机如下:

《Inside the c++ Object model》中指出vptr初始化的时间为:
After invocation of the base class constructors but before execution of user-provided code
or the expansion of members initialized within the member initialization list.

即:
vptr初始化时机在所有基类构造函数之后,但又在自身构造函数或初始化列表之前。
vptr初始化是在初始化列表之前还是之后是跟编译器实现有关的

2)在Base()构造函数中,直接调用foo()虚函数,C++编译器肯定是可以发现的。
猜测:这时候虚函数指针是没有被正确初始化的,因此编译器在基于该虚函数不会有多态行为,会去寻找对应的函数地址。发现为纯虚函数,即编译报错;

3)在Base()构造函数中,直接调用call_foo()函数,为什么编译器没有发现。
这里call_foo()普通函数本身是没有问题的(一种模板方法的设计模式),然后Base()构造函数调用普通函数在编译时也是没有问题的。但是在运行时,Base()调用call_foo(),然后调用纯虚函数foo(),这时候vptr还没有正确初始化,自然运行报错;
疑惑:为什么编译器在编译时无法发现?

错误1

错误源码

#include<vector>
#include<iostream>
#include<thread>
using namespace std;

class Base {
public:
	virtual void func() = 0;


	~Base() {
		this_thread::sleep_for(std::chrono::seconds(10));
	}
};

class Derive :public Base {
public:
	void func() {
		cout << "virtual Derive::func" << endl;
	}
};

void work(Base* pb) {
	while (pb != NULL) {
		pb->func();
	}
}

int main() {
	Base* pd = new Derive();
	pd->func();
	thread th(work, pd);
	delete pd;
	pd = NULL;
	th.join();
}

运行结果

pure virtual method called
terminate called without an active exception
Aborted

说明

如果func只为虚函数,则会出现段错误:

Segmentation fault

原因

析构对象过程,是从子类开始析构的,即到父类析构时,虚函数指针已经被析构了,这时候另外一个线程再去调用虚函数,自然会报错;
因此,多线程编程,需要仔细考虑对象的生命周期,考虑对象被哪些线程管理等等;

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页