何时以及如何通过引用传递参数时调用构造函数?

时间:2014-01-30 10:28:42

标签: c++

我有以下程序

#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”的构造函数。这是怎么回事?

5 个答案:

答案 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 ++灵活性的关键工具。