Undefined behavior means that the compiler should not handle the situation in any particular way.
Here, your compiler, which knew the actual type A in its constructor, was able to embed it in a pure virtual method, rather than calling it via a v-table. This is what will happen if the method is normal virtual and not pure virtual, and this behavior is determined.
Although this would be behavior even through g() , the compiler did not do this for a pure virtual f() function. It's not obligatory.
Simple morality does not cause undefined behavior, and if you want to call f() from the constructor, do not make it pure virtual.
If you want to use your subclasses to implement f() , do not call it from constructor A, but provide this function, which you want to call a different name. Usually not virtual.
source share