在初始化对象后,使用隐式转换而不是赋值运算符调用构造函数有什么意义?

Grz*_*ski 10 c++ c++11

考虑以下示例:

#include <iostream>
using std::cout;
using std::endl;

class CBox
{
public:
    CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0) :
        m_Length {lv}, m_Width {wv}, m_Height {hv}
    {
        cout << "Constructor called" << endl;   
    }

    //CBox& operator=(double)
    //{
    //  cout << "Assignment operator called" << endl;
    //  return *this;
    //}

    double volume() const { return m_Length* m_Width* m_Height; }

private:
    double m_Length;
    double m_Width;
    double m_Height;
};

int main()
{
    CBox box {1.0, 1.0, 1.0}; // no need for initializer list, but put it anyway
    box = 2.0; // why is this calling constructor again ?!
    cout << box.volume() << endl; // prints 2
}
Run Code Online (Sandbox Code Playgroud)

请注意,我故意注释掉了重载的赋值运算符.

执行此程序会产生以下输出:

Constructor called
Constructor called
2
Run Code Online (Sandbox Code Playgroud)

我注意到,即使box对象已经初始化,下一个语句也是故意再次调用构造函数.那是什么意思?

我知道这可以通过explicit关键字来阻止,所以构造函数将是:

explicit CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0) :
        m_Length {lv}, m_Width {wv}, m_Height {hv}
    {
        cout << "Constructor called" << endl;   
    }
Run Code Online (Sandbox Code Playgroud)

但我宁愿期望它会影响像这样的结构:

CBox box = 2.0;
Run Code Online (Sandbox Code Playgroud)

当然,当我取消注释重载赋值运算符时,它优先于构造函数.

Mil*_*nek 17

没有隐含CBox::operator=(double),所以box = 2.0;必须创建一个临时CBox对象.它相当于box = CBox(2.0);.

使你的构造explicit不允许从隐式转换doubleCBox,所以没有相应的赋值操作符存在,你会得到一个编译错误.


Uri*_*her 6

两者之间有很大的不同

CBox box = 2.0
Run Code Online (Sandbox Code Playgroud)

box = 2.0
Run Code Online (Sandbox Code Playgroud)

第一个相当于

CBox box = CBox(2.0)
Run Code Online (Sandbox Code Playgroud)

而第二个相当于

box.operator=(2.0)
Run Code Online (Sandbox Code Playgroud)

由于构造函数的参数具有默认值,因此这相当于定义3个不同的构造函数:

CBox(double, double, double)
CBox(double, double) // the third arguments gets default value
CBox(double) // second and third arguments gets default values
Run Code Online (Sandbox Code Playgroud)

因此,使用单个显式double调用构造函数将调用构造函数,并将为第二个和第三个参数提供默认值.而现在真正的神秘:为什么调用operator=最终结果调用构造函数?

由于您没有明确定义operator=,编译器将自动生成一个赋值运算符,该运算符将另一个CBox作为其单个参数; 这将成为论证的副本.

当您尝试将任何内容分配给CBox对象时,编译器将尝试调用operator=(const CBox&); 既然你提供的是a double而不是a CBox,编译器会尝试将double转换CBox为多种可能的方式之一:

  1. 通过非显式构造函数(在您的情况下第三个)
  2. 通过转换运算符(在这种情况下不相关)
  3. 可能是其他一些我不熟悉的方式.

所以,最终这段代码:

box = 2.0
Run Code Online (Sandbox Code Playgroud)

将被翻译为:

box.operator=(Cbox(2.0))
Run Code Online (Sandbox Code Playgroud)