我正在尝试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 Foo2
。Foo2
按值接受其参数。这意味着n
的MyNodeBase<Node<MyNodeBase>>
子对象的副本就是传递给Foo2
的对象。由于n
中的Foo2
不是Node<MyNodeBase>
,因此通过从GetInt
中的强制类型返回的指针调用CallGetInt
会导致您的程序表现出不确定的行为。
如果将Foo2
更改为通过引用接受其参数,则程序的行为将得到明确定义。
关于c++ - 是否由于混入CRTP和接口(interface)而导致崩溃?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/63393286/