CRTP在Base构造函数中调用子虚拟覆盖

时间:2018-05-21 03:13:16

标签: c++ templates inheritance polymorphism crtp

以下示例产生此运行时错误:

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;
}

另一方面,下一个例子有效;按预期印刷100:

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);
}

也许最有趣的是,如果你没有将init_val()声明为虚拟/覆盖函数,它就可以工作。有人认为这是重复的。我对可能重复的问题的理解是虚拟函数不能在基础构造函数中调用,因为孩子还没有存在。鉴于当init_val不是虚拟代码时代码有效,建议的重复问题不适用于此。

Clang和g ++使用c ++ 17生成相同的行为。

为什么在一个方法中调用它时,在base的构造函数中调用typecast-virtual-function会失败呢?

更新: immibis的建议奏效了。 即将构造函数中对虚拟库的调用更改为:

    static_cast<DERIVED*>(this)->DERIVED::init_val(i)

这是&#34;安全&#34;?它为什么有效?

1 个答案:

答案 0 :(得分:1)

  

这是&#34;安全&#34;?

没有。您正在调用尚不存在的对象上的成员函数。在调用基类构造函数时,派生类尚未形成。因此,您无法在其上调用成员函数。

它只是&#34;工作&#34;意外地;未定义的行为未定义。