当你在删除一个抽象类指针时遇到 “pure virtual method called” 异常,通常是因为在对象的析构过程中调用了纯虚函数。以下是原因分析和解决方法:
1. 问题原因
析构顺序问题:
当派生类对象通过基类(抽象类)指针被删除时,会先调用派生类的析构函数,再调用基类的析构函数。
如果在基类析构函数中(直接或间接)调用了纯虚函数,就会触发此异常。典型场景:
- 基类的析构函数中调用了某个虚函数,而该虚函数在派生类中已被覆盖为纯虚函数。
- 在多线程环境中,对象可能在析构过程中被其他线程访问。
- 基类的析构函数中调用了某个虚函数,而该虚函数在派生类中已被覆盖为纯虚函数。
2. 示例代码(错误场景)
class AbstractBase {
public:
virtual ~AbstractBase() {
// 错误:在基类析构中调用纯虚函数
pureVirtual();
}
virtual void pureVirtual() = 0; // 纯虚函数
};
class Derived : public AbstractBase {
public:
void pureVirtual() override {} // 实现纯虚函数
};
int main() {
AbstractBase* obj = new Derived();
delete obj; // 触发 "pure virtual method called"
return 0;
}
3. 解决方法
(1) 避免在析构中调用虚函数
- 修改基类析构逻辑:确保基类的析构函数不调用任何可能被子类重写为纯虚函数的成员。
class AbstractBase {
public:
virtual ~AbstractBase() {
// 不再调用 pureVirtual()
}
};
(2) 将纯虚函数改为非纯虚并提供默认实现
class AbstractBase {
public:
virtual ~AbstractBase() = default;
virtual void pureVirtual() {} // 非纯虚,提供空实现
};
(3) C++11⁄14+:用 override
+ final
明确禁止派生类修改关键行为
class AbstractBase {
public:
virtual ~AbstractBase() = default;
virtual void criticalFunction() final { /* ... */ } // 禁止派生类重写
};
4. 多线程场景的额外保护
如果对象可能被多线程访问,需确保析构时没有其他线程正在调用成员函数:
class ThreadSafeDerived : public AbstractBase {
public:
~ThreadSafeDerived() {
std::lock_guard<std::mutex> lock(mutex_);
// ...析构操作...
}
private:
std::mutex mutex_;
};
5. C++核心准则参考
- C.35: A base class destructor should be either public and virtual, or protected and non-virtual
- S.123: Don’t call virtual functions during construction or destruction
通过以上方法可以避免该异常。
内容由零声教学AI助手提供,问题来源于学员提问