C++声明用户定义的class对象时使用=赋值初始化的过程是什么?

C++ what's the process when declaring a user-defined class object using = assignment to initialize?

我定义了一个class命名的String,我声明了一个String对象使用=赋值来初始化它,但是我对它背后的过程有一些疑问。让我们看看代码:

class String{
public:
    String() :str(""){ cout << "default constructor" << endl; }
    String(int n);
    String(const char *p);

    String(const String &x) :str(x.str)
    {
        cout << "copy constructor" << endl;
    }
    String& operator=(const String &x)
    {
        str = x.str;
        cout << "operator =" << endl;
        return *this;
    }
    string getStr() const
    {
        return str;
    }
private:
    string str;
};

ostream& operator<<(ostream &o,const String &x)
{
    o << x.getStr();
    return o;
}

String::String(int n)
{
    stringstream ss;
    ss << n;
    ss >> str;
    ss.clear();
    ss.str("");
    cout << "String(int n)" << endl;
}

String::String(const char *p)
{
    str = *p;
}

int _tmain(int argc, _TCHAR* argv[])
{
    String s6;
    s6 = 10;
    cout << s6 << endl;
    return 0;
}

结果如下图:

嗯,这个好理解,先调用默认构造函数,再调用String::String(int n)构造函数,最后调用复制赋值。 然后我这样修改主函数:

int _tmain(int argc, _TCHAR* argv[])
{
    String s6=10;
    cout << s6 << endl;
    return 0;
}

结果如下图:

我不明白为什么它不调用复制赋值,在这种情况下它背后的过程是什么?

你混淆了赋值和初始化。

String s6=10;不是赋值,而是初始化;更准确地说,copy intialization

1) when a named variable (automatic, static, or thread-local) of a non-reference type T is declared with the initializer consisting of an equals sign followed by an expression.

所以 s6 是由适当的构造函数 intialized/constructed,即 String::String(int),这里没有赋值。

这不是作业,这是 copy initialization

T object = other; (1)

...

If T is a class type, and the cv-unqualified version of the type of other is not T or derived from T, or if T is non-class type, but the type of other is a class type, user-defined conversion sequences that can convert from the type of other to T (or to a type derived from T if T is a class type and a conversion function is available) are examined and the best one is selected through overload resolution. The result of the conversion, which is a prvalue temporary (until C++17) prvalue expression (since C++17) if a converting constructor was used, is then used to direct-initialize the object.

在您的情况下 T object = other 转换为 T object(T(other)) (direct initialization)。但是

The last step is usually optimized out and the result of the conversion is constructed directly in the memory allocated for the target object, but the appropriate constructor (move or copy) is required to be accessible even though it's not used. (until C++17)

选择的最后一句话解释了为什么在直接初始化期间没有调用复制构造函数。