使用CRTP时确保安全

时间:2016-04-19 03:10:45

标签: c++ crtp

考虑使用CRTP进行以下代码片段

#include <iostream>

struct Alone
{
    Alone() { std::cout << "Alone constructor called" << std::endl; }
    int me {10};
};

struct Dependant
{
    explicit Dependant(const Alone& alone)
        : ref_alone(alone)
    { std::cout << "Dependant called with alone's me = " << alone.me << std::endl; }
    const Alone& ref_alone;
    void print() { std::cout << ref_alone.me << std::endl; }
};

template <typename D>
struct Base
{
    Base() { std::cout << "Base constructor called" << std::endl; }

    D* getDerived() { return static_cast<D*>(this); }
    Dependant f { getDerived()->alone };
    void print() { f.print(); }
};

struct Derived : Base <Derived>
{
    Derived() { std::cout << "Derived constructor called "  << std::endl; }
    Alone alone {};
    void print() { Base::print(); };
};

int main()
{
    Derived d;
    d.print();
}

原始链接http://coliru.stacked-crooked.com/a/79f8ba2d9c38b965

我先得到一个基本问题

  • 使用继承时如何进行内存分配?我知道构造函数是从Base到Derived调用的,但是当我做

    时似乎
      

    派生d;

    分配 sizeof(D)的内存,然后调用构造函数。我的理解在这里是否正确? (这可以解释打印未初始化的成员)

  • 考虑到上面的例子,你会建议/推荐CRTP的最佳实践吗?

1 个答案:

答案 0 :(得分:1)

  分配

等于sizeof(D)的内存,然后调用构造函数

它还有什么可能起作用?你不能在内存中构造一个尚未分配的对象。内存分配总是在对象构建之前进行。

  

考虑到上面的例子,你会建议/推荐CRTP的最佳实践吗?

CRTP的标准做法:不要在构造函数/析构函数中调用CRTP。虚拟功能也是如此。虚拟是动态多态,而CRTP是静态多态。但是他们都使用相同的基本机制:一个定义派生类必须实现的接口的基类。

就像虚函数一样,试图在构造函数/析构函数中调用它不会做你的意思。唯一的区别是,对于虚函数,编译器实际上会阻止您获取未定义的行为。而对于CRTP,你只会破产。

请注意,这包括默认成员初始值设定项,出于非聚合的目的,它只是构造函数初始化列表的简写。