我有以下程序
#include <iostream>
class A
{
public:
A(int n = 0)
: m_n(n)
{
std::cout << 'd';
}
A(const A& a)
: m_n(a.m_n)
{
std::cout << 'c';
}
private:
int m_n;
};
void f(const A &a1, const A &a2 = A())
{
}
int main()
{
f(3);
std::cout << std::endl;
return 0;
}
该程序生成“dd”作为输出。我不明白为什么为函数“f”的第一个参数调用构造函数。我传递一个整数“3”,它调用带有参数“3”的“a1”的构造函数。这是怎么回事?
答案 0 :(得分:2)
此构造函数
A(int n = 0)
: m_n(n)
{
std::cout << 'd';
}
是转换构造函数。它将int类型的对象(在这种情况下,此对象由参数n指定)转换为类型A的对象。因此,当您将函数f调用为
时f( 3 );
编译器发现有一个具有此类名称的函数具有const A&amp;类型的第一个参数。因此它尝试将3转换为A类型的对象,并且由于它隐式调用的转换构造函数,它可以执行此操作。然后将对此临时对象的引用传递给该函数。如果要将构造函数声明为
explicit A(int n = 0)
: m_n(n)
{
std::cout << 'd';
}
然后编译器无法隐式调用它并发出错误。
对于第二个参数,它有一个默认参数:A类型的临时对象。编译器可以将const引用绑定到临时对象。
因此在您的代码中,转换构造函数被调用两次。对于第一个参数,它由编译器隐式调用,而第二个参数则显式调用,因为它的调用被指定为默认参数。 复制构造函数不参与此过程。您不复制任何对象。您只能使用const引用绑定临时对象。
答案 1 :(得分:1)
A::A(int n);
设置为n
的情况下调用 3
。该对象是一个传递给f
的临时对象,它通过对A
的const引用获取它。
在您的代码中,永远不会调用复制构造函数。
答案 2 :(得分:0)
编译器尝试将函数参数与给定的匹配。他得到int 3
但需要A(int n)
或A(const A& a)
。编译器然后注意到他可以轻松地创建临时对象A
,并且int
并将其提供给函数。这就是它的作用。
答案 3 :(得分:0)
对于产生输出的运行,根本不调用复制构造函数。
对此的解释是复制构造函数调用(对于第二个参数)是 elided ,已经优化了。解释是两个形式参数都是引用,正如Steve Jessop在评论中暗示指出的那样(我有点失明)。
f
的第一个和第二个形式参数都是通过调用int
参数构造函数构造的,因为它兼作默认构造函数。
答案 4 :(得分:0)
按值传递对象时,将使用其中一个可用构造函数创建副本。这可能是一个复制构造函数(它需要一个A
并导致另一个A
),或者它可能是一个构造函数,它采取完全不同的东西(并产生A
)!
这是对象构造的基本事实,与引用无关:
struct A
{
A(int x) {};
};
void foo(A a) {}
int main()
{
foo(3); // OK
}
在你的情况下,你没有通过值传递,但是 C ++仍然试图为你形成一个A
,以便让你的函数调用起作用。成功时(如此处),结果是临时A
(可以绑定到const
引用)。
最终,这就像:
int main()
{
A a(3);
foo(a);
}
能够将事物传递给然后应用了转换的函数调用是C ++灵活性的关键工具。