C++ 确保使用CRTP时的安全

C++ 确保使用CRTP时的安全,c++,crtp,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(al

考虑下面使用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();
}
#包括
单结构
{
单独(){std::cout
分配相当于sizeof(D)的内存,然后调用构造函数


否则它怎么可能工作呢?你不能在内存中构造一个尚未分配的对象。内存分配总是在对象构造之前

考虑到上述示例,您是否建议/推荐CRTP的最佳实践

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

就像在虚拟函数中一样,试图在构造函数/析构函数中调用它不会达到你的目的。唯一的区别是,在虚拟函数中,编译器实际上会阻止你获得未定义的行为。而在CRTP中,你只会得到破坏


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

您在成员变量上使用静态初始值设定项,我很惊讶甚至会编译。正确的初始化方法是将其放入构造函数初始值设定项列表:
only():me(10){…}
发布示例代码。@markRansom嗯..什么?想解释一下吗?(提供链接,如果有)。我这样做已经有一段时间了,而且效果很好。@skgbanga:他基本上是在指出一个事实,就是你没有给你的问题贴上C++11的标签,默认成员初始值设定项是C++11的一项功能。但坦率地说,这是2016年,应该没有必要。@NicolBolas没错,我有点陷入了过去。C++11已经这是我第一次接触到这种语法。“它还能怎么工作?”我想我在解释我的问题时不太清楚。当我说内存相当于sizeof(D)时,我的意思是,一次分配该对象的整个内存,然后逐段进行构造,或者分配和构造都是逐段进行的,但分配的内存保证是连续的。(尽管可能性不大)@skgbanga:当你用
malloc
分配一个对象时,你传递给它实际对象的整个大小。当你用
new
分配一个对象时,
操作符new
传递给被分配对象的整个大小。为什么你认为这对堆栈对象会有所不同?我实际上没有,但我想确认一下来自某人。谢谢你的回答。接下来的一个问题是:有没有一种编程方式可以确保每当有人试图“访问基的构造函数/析构函数中的派生成员”时,我都会收到编译错误?