我正在尝试CRTP并将其与接口(interface)混合使用,但无法解释为什么该程序崩溃(在Clang,GCC和MSVC中)。在最新的Clang和GCC中,它使用-Wall,-Wextra进行构建而不会发出警告。我的猜测是虚拟方法调用未解决,但我无法解释原因(如果从接口(interface)中删除了GetInt(),则不会崩溃)。在调试器中,我看到崩溃发生在static_cast<T*>(this)->GetInt()行上。

#include <iostream>

class INode
{
public:
    virtual int GetInt() = 0;
protected:
    ~INode() {}
};

template<template<class> typename NodeBase>
class Node : public INode, public NodeBase<Node<NodeBase>>
{
public:
    int GetInt() override { return 42; }
};

template<typename T>
class MyNodeBase
{
public:
    int CallGetInt() {
        return static_cast<T*>(this)->GetInt();
    }
};

template<template<class> typename NodeBase>
int Foo1(Node<NodeBase> n) {
    return n.CallGetInt();
}

template<typename T>
int Foo2(MyNodeBase<T> n) {
    return n.CallGetInt();
}

int main() {
    Node<MyNodeBase> n;
    std::cout << Foo1(n) << std::endl; // ok
    std::cout << Foo2(n) << std::endl; // crash
}

最佳答案

您的n通话中就是slicing Foo2Foo2按值接受其参数。这意味着nMyNodeBase<Node<MyNodeBase>>子对象的副本就是传递给Foo2的对象。由于n中的Foo2不是Node<MyNodeBase>,因此通过从GetInt中的强制类型返回的指针调用CallGetInt会导致您的程序表现出不确定的行为。
如果将Foo2更改为通过引用接受其参数,则程序的行为将得到明确定义。

关于c++ - 是否由于混入CRTP和接口(interface)而导致崩溃?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/63393286/

10-09 06:36