The following example produces this run-time error:
pure virtual method called
terminate called without an active exception
e.g.
template<class DERIVED>
struct Base {
int val;
Base(int i) : val(static_cast<DERIVED*>(this)->init_val(i)) {}
virtual int init_val(int i) = 0;
};
struct Derived : public Base<Derived> {
Derived(int i): Base<Derived>(i) {}
int init_val(int i) override {return i;}
};
int main(){
Derived d{100};
cout << d.val;
}
On the other hand, this next example works; printing 100 as expected:
template<class DERIVED>
struct Base {
int foo(int i){return static_cast<DERIVED*>(this)->bar(i);}
virtual int bar(int i) = 0;
};
struct Derived : public Base<Derived> {
int bar(int i) override {return i;}
};
int main(){
Derived d;
cout << d.foo(100);
}
Perhaps the most interesting is that it works if you don't declare init_val() as a virtual/overriden function. It has been suggested that this is duplicate. My understanding of the potentially duplicated question is that virtual functions can't be called in a base constructor because the child doesn't exist yet. In light of the fact that the code works when init_val is not virtual the proposed duplicated question does not apply here.
Clang and g++ produce the same behavior using c++17.
Why does calling the typecast-virtual-function within the base's constructor fail when calling it in a method works?
UPDATE: The suggestion by immibis worked. i.e. changing the call to virtual base in the constructor to this:
static_cast<DERIVED*>(this)->DERIVED::init_val(i)
Is this "safe"? Why does it work?