使用复制构造函数并且存在虚拟函数时,错误“在所有控制路径上递归”

use*_*041 5 c++ templates virtual-functions multiple-inheritance visual-c++

下面的错误使我感到困惑。这是更复杂的代码的一小段。对我来说似乎很奇怪,只有同时存在模板化构造函数和虚拟方法才导致错误,并且仅在复制初始化对象时才引起错误。

有没有人有一个想法?谢谢。

    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;
Run Code Online (Sandbox Code Playgroud)

下一行main()

      A a=c; 
Run Code Online (Sandbox Code Playgroud)

如果这两个行都标记为// 1和,则将触发以下错误// 2

warning C4717: 'C::C' : recursive on all control paths, function will cause runtime stack overflow 
Run Code Online (Sandbox Code Playgroud)

但是,在中使用以下代码时main(),不会出现错误:

      A a;
      a=c;
    }
Run Code Online (Sandbox Code Playgroud)

con*_*gus 5

您所拥有的是复制删除和创建参数副本的构造函数的令人讨厌的融合。

首先,让我们澄清一个误区:A a = c;就是等于A a; a = c;。第一个调用复制ctor,第二个调用赋值运算符。亲自使用此代码示例

构造函数A::A<T>(T)可以T在调用它时复制它。不幸的是,如果使用A参数调用它(或在示例C中为-a A),则该参数将尝试复制自身,然后A::A<T>(T)再次调用,再次复制自身,直到堆栈溢出。

如果没有virtual void f()in,为什么不发生这种情况B?这是复制省略的副作用,它是实现相关的功能。有了虚拟方法,Visual Studio可能已经足够决定不取消副本,但是无论如何您都不应依赖它。这就是为什么强烈建议不要对复制ctor有明显的副作用

万一您在寻找解决方案,可以通过更改A::A<T>(T)以获取参考来删除副本,例如A::A<T>(T&)。更好const T&的做法是,使用a,因为这有助于确保ctor中没有副作用(因为您无法修改T)。

  • @CongXu。否。无论多么专门化或何种参数类型,模板构造函数都不能是副本构造函数。 (2认同)