以下错误让我感到困惑。这是一段更复杂的代码。我觉得很奇怪,只有模板化构造函数和虚方法都存在错误,并且只有在复制初始化对象时才会出现错误。
有没有人有想法?感谢。
class A
{
long *p;
public:
A():p(0)
{
}
template<class T>
A(T val):p(val)// 1
{
}
operator long*()
{
return p;
}
};
class B
{
virtual void f()// 2
{
}
};
class C : public A, public B
{
};
void main()
{
C c;
main()
中的下一行是
A a=c;
如果标记为// 1
和// 2
的行都存在,则会触发以下错误:
warning C4717: 'C::C' : recursive on all control paths, function will cause runtime stack overflow
但是在main()
中使用以下内容时,没有错误:
A a;
a=c;
}
答案 0 :(得分:4)
你所拥有的是copy elision与制作参数副本的构造函数的令人讨厌的融合。
首先,让我们澄清一个误解:A a = c;
不等同于A a; a = c;
。第一个调用copy ctor,第二个调用赋值运算符。使用this code sample查看自己。
构造函数A::A<T>(T)
可以在调用时复制T
。不幸的是,如果您使用A
参数(或在您的示例C
中调用它,即A
),参数将尝试复制自身,调用A::A<T>(T)
再次,它再次复制自己,再次......直到堆栈溢出。
如果virtual void f()
中没有B
,为什么不会发生这种情况?这是copy elision的副作用,它是一个依赖于实现的功能。拥有虚拟方法可能已经足以让visual studio决定不删除副本,但无论如何你不应该依赖它。这就是你strongly advised not to have observable side-effects for copy ctors的原因。
如果您正在寻找解决方案,可以通过更改A::A<T>(T)
来删除副本以获取参考,例如A::A<T>(T&)
。更好的是,选择const T&
,因为这有助于确保ctor中没有副作用(因为您无法修改T
)。
答案 1 :(得分:1)
A a=c; // this results in A::A(C c) template constructor instantiation.
之后是递归,因为要制作副本,你需要制作副本,你需要复制....:)
如需正确使用,请参阅this。