C++调用纯虚函数未抛异常 如何触发pure virtual function call错误
问题原因
你写的测试代码没有触发错误,本质是对C构造阶段虚函数调用规则的理解有偏差:
C构造类对象时,会按照继承链从最顶层基类到最底层派生类逐层执行构造,每进入一层类的构造阶段,对象的虚表指针就会指向当前层对应的虚函数表:
- 先执行基类
A的构造时,虚表中f()是纯虚函数入口,没有可执行的实现 - 等
A构造完成,进入派生类A1的构造阶段时,虚表已经更新为A1的版本,f()已经指向你写的A1::f()实现,这时候你在A1构造函数里调用f(),不管是静态决议还是动态分派,都会调用到已经实现的A1::f(),自然能正常输出,不会报错。
所谓“构造函数里调用虚函数会触发pure virtual function call”是有前提的:调用发生时,当前构造阶段对应的类层级中,被调用的虚函数还是纯虚、没有任何实现。
触发pure virtual function call的常见写法
只要满足上面说的前提,就能触发这个运行时错误,注意不同编译器/运行时的表现有区别:MSVC、Windows下MinGW的C运行时会明确弹出"pure virtual function call"的错误提示,Linux下g可能直接在编译期拦截这类明显错误,或者运行时触发段错误。
写法1:直接在定义纯虚函数的基类构造函数中调用该纯虚函数
#include <cstdio> class A{ virtual void f() = 0; public: A() { f(); // 执行A的构造时,f()还是纯虚,无实现 } }; class A1 : public A{ public: void f() override {printf("virtual function");} }; int main(){ A1 a; return 0; }
写法2:通过间接调用绕过编译期检查,在基类构造阶段调用纯虚函数
直接在构造函数里写纯虚调用很容易被编译器在编译阶段拦截,通过成员函数、回调、指针间接调用的场景更隐蔽,也是实际开发中最容易踩坑的情况:
#include <cstdio> class A{ virtual void f() = 0; public: void invoke() { f(); // 封装一层间接调用 } A() { invoke(); // 基类构造时通过其他成员函数调用纯虚f } }; class A1 : public A{ public: void f() override {printf("virtual function");} }; int main(){ A1 a; return 0; }
类似的,构造函数里把this指针传给外部函数、注册为回调,外部代码在构造完成前通过这个指针调用纯虚函数,也会触发同样错误。
另外补充:析构阶段也会出现同类错误——析构顺序是从派生类到基类逐层执行,当执行到基类析构函数时,虚表已经回退到基类版本,这时候调用基类定义的纯虚函数,一样会触发pure virtual function call。
内容的提问来源于stack exchange,提问作者Troskyvs
相关产品推荐
相关产品推荐

