【问题标题】:Why did the copy operator get called?为什么要调用复制操作员?
【发布时间】:2019-05-15 20:44:12
【问题描述】:

在最后一行myA = foo(myOtherB);,函数将返回类型为A的对象,因此;这就像说`myA = input,但是为什么是复制构造函数呢?

输出:

B foo()
 A copy ctor //what calls this?
 A op=

要调用复制构造函数,我们必须在初始化期间使用赋值运算符,例如:B newB = myOtherB;

#include <iostream>
using namespace std;

class A {
public:
 A() { cout << "A ctor" << endl; }
 A(const A& a) { cout << "A copy ctor" << endl; }
 virtual ~A() { cout << "A dtor" << endl; }
 virtual void foo() { cout << "A foo()" << endl; }
 virtual A& operator=(const A& rhs) { cout << "A op=" << endl; }
};

class B : public A {
public:
 B() { cout << "B ctor" << endl; }
 virtual ~B() { cout << "B dtor" << endl; }
 virtual void foo() { cout << "B foo()" << endl; }
 protected:
 A mInstanceOfA; // don't forget about me!
};

A foo(A& input) {
 input.foo();
 return input;
}
int main() {
 B myB;
 B myOtherB;
 A myA;
 myOtherB = myB;
 myA = foo(myOtherB);
}

【问题讨论】:

  • 这段代码无法编译
  • 查看foo的返回类型。注意到有什么遗漏了吗?
  • foo() 返回一个A 对象按值,而不是按引用,因此是@ 的复制正在返回 987654328@,并且该副本需要调用复制构造函数。

标签: c++ class oop virtual


【解决方案1】:

在最后一行myA = foo(myOtherB);,函数将返回类型为B的对象

不正确。您的函数按值返回 A 类型的对象。这意味着,您为这个对象提供的任何值都将用于构造该确切类型的新对象。换句话说:

int foo(float a) {
    return a + 0.5;
}

int u;

u = foo(9.3);

// u has a value of 10

不要指望u 持有 int 不能保存的值。

如果你使用用户定义的类型也是一样的:

A foo(A& input) {
 input.foo();
 return input; // this expression returns a new A
               // using the value of `input`
}

A myA;

myA = foo(myOtherB);

// why would `myA` be anything else than the value of an A?

那么,这里发生了什么?

B foo()
 A copy ctor //what calls this?
 A op=
A foo(A& input) {
 input.foo(); // prints B foo, virtual call. a reference to A that
              // points to an object of subclass type B

 return input; // copy `input` into the return value object
}

然后,operator= 被调用。

【讨论】:

  • 所以返回输入;就像说 // myA = myOtherB(input);我的意思是当我们返回一个对象时,另一个对象将使用复制构造函数接收它,对吗?
  • 好吧,myA 已经构造好了,所以调用myA 调用运算符,并以副本为参数
【解决方案2】:

cppreference

具体来说:

每当一个对象从同类型的另一个对象初始化(通过直接初始化或复制初始化)时,都会调用复制构造函数(除非重载决议选择了更好的匹配或省略了调用),这包括

  • 初始化:T a = b;或 T a(b);,其中 b 是 T 类型;
  • 函数参数传递:f(a);,其中 a 是 T 类型,f 是 void f(T t);
  • 函数返回:返回一个;在诸如 T f() 之类的函数中,其中 a 的类型为 T,它没有移动构造函数。

【讨论】:

  • 所以返回输入;就像说 // myA = myOtherB(input);或者返回一个对象总是会调用拷贝构造函数
  • 返回对象的函数使用复制构造函数创建一个临时对象。然后= 运算符将临时对象分配给您的。
  • @cj.vaughter 实际上,这不是真的,请参阅 Guillaume Racicot 的回答,尤其是最后一部分。事实上,foo 返回其输入参数的副本,该副本生成对A 的复制构造函数的调用。否则,副本将为elided
  • 哇,不知道我怎么忽略了这一点,它就在引文中。感谢您指出这一点。
猜你喜欢
  • 1970-01-01
  • 2015-08-26
  • 2014-01-28
  • 2011-11-25
  • 2012-03-17
  • 2013-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多