C++构造函数调用和对象创建

Vin*_*ddy 4 c++ initialization copy-constructor

class Test{
    public :
        int x;  
        Test()
        {
            x = 0;
            cout<<"constructor with no arguments called"<<endl;
        }
        Test(int xx)
        {
            x = xx;
            cout<<"constructor with single int argument called"<<endl;
        }

};


int main()
{
    Test a(10);
    Test aa = 10;
}
Run Code Online (Sandbox Code Playgroud)

输出:程序编译和输出

带有单个int参数的构造函数

带有单个int参数的构造函数

但现在

class Test{
    public :
        int x;  
        Test()
        {
            x = 0;
            cout<<"constructor with no arguments called"<<endl;
        }
        Test(int xx)
        {
            x = xx;
            cout<<"constructor with single int argument called"<<endl;
        }

        Test( Test& xx)
        {
            x = xx.x;
            cout<<"copy constructor called"<<endl;
        }


};


int main()
{
    Test a(10);
    Test aa = 10;
}
Run Code Online (Sandbox Code Playgroud)

编译失败.

constructorinvokings.cc:36:7: error: no viable constructor copying variable of type 'Test'
        Test aa = 10;
             ^    ~~
constructorinvokings.cc:23:3: note: candidate constructor not viable: no known conversion from 'Test' to 'Test &' for 1st
      argument
                Test( Test& xx)
                ^
1 error generated.
Run Code Online (Sandbox Code Playgroud)

我是C++的新手.

不是测试a(10)和测试aa = 10; 相同?

为什么添加复制构造函数与Test aa = 10冲突?

如果我将Test(Test&xx)修改为Test(const Test&xx)它正在工作.但是当我们尝试使用整数参数调用构造函数时,为什么编译器会检查复制构造函数签名.

请澄清

提前致谢.

Omn*_*ous 6

到目前为止你得到的所有答案都过于复杂和/或有些误导.

在第一个构造/初始化中:

T a(10);
Run Code Online (Sandbox Code Playgroud)

非常明显的事情发生了.第二个构造/初始化更有趣:

T aa = 10;
Run Code Online (Sandbox Code Playgroud)

这相当于:

T aa(T(10));
Run Code Online (Sandbox Code Playgroud)

这意味着您创建T类型的临时对象,然后构造aa为此临时对象的副本.这意味着调用了复制构造函数.

C++有一个默认的复制构造函数,当你没有显式声明时,它会为类创建.因此,即使第一个版本class T没有声明复制构造函数,仍然有一个.编译器声明的那个具有此签名T(const T &).

现在,在第二种情况下,您声明了一个看起来像复制构造函数的东西,您可以将参数设为a T &,而不是a const T &.这意味着编译器在尝试编译第二个表达式时会尝试使用您的复制构造函数,但它不能.它抱怨你声明的复制构造函数需要一个非const参数,并且它给出的参数是const.所以它失败了.

另一个规则是在编译器将初始化转换为T aa(T(10));它之后,然后允许将其转换为T aa(10);.这被称为"复制省略".在某些情况下,允许编译器跳过对复制构造函数的调用.但它只能在验证表达式是否正确形成后才能执行此操作,并且在复制构造函数调用仍然存在时不会生成任何编译器错误.因此,这是一个优化步骤,可能会影响程序的哪些部分运行,但不能影响哪些程序有效以及哪些程序有错误(至少从它们是否编译的角度来看).

  • @Vineel Kumar Reddy:因为编译器然后意识到它可以省略复制构造函数.首先,它必须确保表达式是有效的,然后它可以确定是否任何复制构造函数调用是多余的.它删除(又名elides)多余的.管理复制构造函数调用的特定规则可以被认为是多余的. (2认同)