2014-01-30 2 views
1

У меня есть следующая программаКогда и как вызван конструктор при передаче аргументов по ссылке?

#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» и вызывает конструктор для «a1» с аргументом «3». Как это происходит?

+3

Копия c'tor не называется. Вызывается «преобразование из int» c'tor. – StoryTeller

+0

Где вы видите копию c'tor? 'c' не входит в выход. – Erbureth

+0

Я не понимаю проблему. Ничто не кажется странным или запутанным здесь, и вы не сказали нам, что это такое, что вы считаете странным. –

ответ

1

A::A(int n); вызывается с n установлен на 3. Объект является временным, который передается в f, который принимает его с помощью ссылки const на A.

В вашем коде конструктор копирования никогда не вызывается.

0

Компилятор пытается сопоставить параметр функции с тем, что было дано. Он получил int 3, но ему нужно либо A(int n), либо A(const A& a). Затем компилятор замечает, что он может легко создать временный объект A, который принимает и int, и передает это функции. Так оно и есть.

0

Конструктор копирования не вызывается вообще, для запуска, который произвел ваш выход.

И объяснение этого заключается в том, что вызов конструктора копирования (для второго аргумента) был удален от, оптимизирован. Объяснение состоит в том, что оба официальных аргумента являются ссылками, как неявно указывал Стив Джессоп в комментариях (я был немного слеп).

Как первый, так и второй формальные аргументы f построены с вызовами конструктора аргументов int, поскольку он по умолчанию является конструктором по умолчанию.

+0

Вы уверены, что для второго аргумента есть редактор конструктора? Я не думаю, что для реализации разрешено вызывать конструктор копирования для этого кода. –

+0

@SteveJessop: О, это ссылка. не видел этого. благодаря! –

1

Этот конструктор

A(int n = 0) 
    : m_n(n) 
{ 
    std::cout << 'd'; 
} 

является конструктором преобразования. Он преобразует объект типа Int (в данном случае это объект, заданный параметр п) к объекту типа А. Таким образом, при вызове функции F в

f(3); 

компилятор видит, что есть функция с такими имя, которое имеет первый параметр типа const A &. Поэтому он пытается преобразовать 3 в объект типа A, и он может это сделать из-за конструктора преобразования, который он вызывает неявно. Затем ссылка на этот временный объект передается функции. Если бы объявить конструктор, как

explicit A(int n = 0) 
    : m_n(n) 
{ 
    std::cout << 'd'; 
} 

, то компилятор не может назвать это неявно и выдаст ошибку.

Что касается второго параметра, то он имеет аргумент по умолчанию: временный объект типа A. Компилятор может связывать ссылку const со временным объектом.

Итак, в вашем коде конструктор преобразования вызывается дважды. Для первого аргумента он неявно называется компилятором, а для второго аргумента он явно указан, потому что его вызов указан как аргумент по умолчанию. Конструктор копирования не участвует в этом процессе. Вы не копируете какой-либо объект. Вы связываете только временные объекты с ссылками на const.

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); 
} 

Будучи в состоянии передать вещи в вызовы функций, которые тогда преобразование применяется является важным инструментом в гибкости С ++.

Смежные вопросы