3

测试程序是

#include <iostream>
using namespace std;

class A
   {public:
       A (): I(0) {cout << "default construcot" << endl; };
       explicit A (int i): I(i) {cout << "another construcot" << endl; };
       A (const A& a): I(a.I) {cout << "copy constructor" << endl; }
       A& operator = (const A& a)
          {cout << "assignment operator" << endl; 
           if (this == &a) return *this; 
           I = a.I;
           return *this; 
          }
       void show () {cout << I << endl; };
    private:
       int I;
   };

int main ()
   {A a = A(1);
    A b;
    b = A(2);
    a.show();
    b.show();
    return 0;
   }

输出

another construcot
default construcot
another construcot
assignment operator
1
2

显示,与 'b' 不同的对象 'a' 是从 A(1) “直接”构造的,无需执行赋值运算符。但是复制构造函数也没有执行。为什么?在这种情况下,有没有办法强制执行赋值运算符?如果我写的话,我会期待这样的行为

A a (1);

但我想要

A a = A(1);

这必须不同于第一种情况。或不?

(事实上​​,当我有一个从 A 派生的类 B 并希望 A 的赋值运算符处理像 A a = B(...) 这样的声明时,就会出现问题。)

4

5 回答 5

6

这个

A a = A(1);

不等于:

A a;
a = A(1);

在第二种情况下=是运算符,在第一种情况下=不是运算符。在第一个语句中,它是一个初始化语法。编译器可能会调用复制构造函数,但它可以优化它,因为它是语言允许的地方之一(RVO、异常抛出等)。

于 2010-12-27T19:20:40.120 回答
3

为什么

该标准允许编译器优化复制构造。不是这不是分配,因为它是声明的一部分(因此,如果未进行优化,它将导致临时对象,然后将临时对象复制到 a 中)。

在这种情况下,有没有办法强制执行赋值运算符。

这将取决于您的编译器。但是我不知道有什么可以让您强制执行此操作(但是我从未尝试将其关闭)。尝试关闭编译器正在执行的所有优化。

如果我写: A a (1);

该标准明确指出您的版本可以优化为此。

我有一个从 A 派生的 B 类,并希望 A 的赋值运算符处理像 A a = B(...) 这样的声明。)

如果你这样做,你将切片 B 并分配 B 对象的 A 部分。
你想使用参考吗?

A const& a = B();
于 2010-12-27T19:31:21.430 回答
1

我希望A a(1);A a = 1;完全一样,它是由标准保证的。

于 2010-12-27T21:36:10.660 回答
1

为什么?因为编译器可以很自由地这样做,而且大多数都这样做。

你能强迫吗?不。

于 2010-12-27T19:18:02.680 回答
1

它在语言中明确定义,编译器基本上可以随时删除复制结构,并且第一种形式无论如何都是初始化语法。但是,当您使用实际派生实例调用它时,您可能会发现此行为已被删除,因为这样做会影响程序的正确性。

于 2010-12-27T19:29:22.557 回答