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

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

提问人:Frank 提问时间:5/10/2017 最后编辑:songyuanyaoFrank 更新时间:5/10/2017 访问量:420

问:

我定义了一个名为 String 的类,并使用 = assignment 声明了一个 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;
}

结果如下图所示:

result1

嗯,这是可以理解的,首先调用默认构造函数,然后调用 String::String(int n) 构造函数,最后调用复制赋值。 然后我像这样修改 main 函数:

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

结果如下图所示:result2

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

C++ 构造函数 初始化 变量 值 赋值运算符

评论

0赞 M.M 5/10/2017
您的代码(如发布的那样)无法编译。请发布 MCVE

答:

4赞 songyuanyao 5/10/2017 #1

你混淆了赋值和初始化。

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

1) 当非引用类型的命名变量(自动、静态或线程局部)声明时,初始值设定项由等号后跟表达式组成。T

因此,由适当的构造函数初始化/构造,即,此处没有赋值。s6String::String(int)

2赞 DAle 5/10/2017 #2

这不是分配,这是复制初始化

T object = other;(1)

...

如果 T 是类类型,并且 other 类型的 cv 非限定版本不是 T 或派生 T,或者如果 是非类类型,但 的类型是类类型,则检查可以从 other 类型转换为(或派生自 if 的类型是类类型且转换函数可用)的用户定义的转换序列,并通过重载解析选择最佳序列。转换的结果是 prvalue 临时(直到 C++17)prvalue 表达式(自 C++ 17 起)(如果使用转换构造函数),则用于直接初始化对象。TotherTTT

在您的情况下转换为(直接初始化)。但T object = otherT object(T(other))

最后一步通常是优化的,转换结果直接在为目标对象分配的内存中构造,但即使未使用适当的构造函数(移动或复制),也需要可访问。(直到 C++17)

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