2009-04-16 5 views
14

Я знаю, что если вы выйдете из списка инициализации в конструкторе no-arg, будет вызываться конструктор по умолчанию этого члена.Списки инициализации конструктора конструктора

Составляют ли копии конструкторы также вызов конструктора копирования элементов, или же они также называют конструктор по умолчанию?

class myClass { 
    private: 
    someClass a; 
    someOtherClass b; 
    public: 
    myClass() : a(DEFAULT_A) {} //implied is b() 
    myClass(const myClass& mc) : a(mc.a) {} //implied is b(mc.b)??? or is it b()? 
} 
+2

См. Http://stackoverflow.com/questions/563221/is-there-an-implicit-default-constructor-in-c/563320#563320 –

ответ

23

Явные конструкторы копирования не вызывают конструкторы копирования для членов.

Когда вы вводите тело конструктора, каждый член этого класса будет инициализирован. То есть, как только вы доберетесь до {, вы гарантированно, что все ваши члены были инициализированы.

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

Вот небольшая программа, которую можно скопировать и вставить куда-нибудь и возиться с:

#include <iostream> 

class Foo { 
public: 
    Foo() { 
     std::cout << "In Foo::Foo()" << std::endl; 
    } 

    Foo(const Foo& rhs) { 
     std::cout << "In Foo::Foo(const Foo&)" << std::endl; 
    } 
}; 

class Bar { 
public: 
    Bar() { 
     std::cout << "In Bar::Bar()" << std::endl; 
    } 

    Bar(const Bar& rhs) { 
     std::cout << "In Bar::Bar(const Bar&)" << std::endl; 
    } 
}; 

class Baz { 
public: 
    Foo foo; 
    Bar bar; 

    Baz() { 
     std::cout << "In Baz::Baz()" << std::endl; 
    } 

    Baz(const Baz& rhs) { 
     std::cout << "In Baz::Baz(const Baz&)" << std::endl; 
    } 
}; 

int main() { 
    Baz baz1; 
    std::cout << "Copying..." << std::endl; 
    Baz baz2(baz1); 
} 

как есть, это печатает:

 
In Foo::Foo() 
In Bar::Bar() 
In Baz::Baz() 
Copying... 
In Foo::Foo() 
In Bar::Bar() 
In Baz::Baz(const Baz&) 

Обратите внимание, что это по умолчанию инициализации членам Baz.

закомментировав явный конструктор копирования, как:

/* 
Baz(const Baz& rhs) { 
    std::cout << "In Baz::Baz(const Baz&)" << std::endl; 
} 
*/ 

Выход будет так:

 
In Foo::Foo() 
In Bar::Bar() 
In Baz::Baz() 
Copying... 
In Foo::Foo(const Foo&) 
In Bar::Bar(const Bar&) 

Он называет копию-конструктор на обоих.

И если мы вновь Baz конструктор копирования и явно скопировать один элемент:

Baz(const Baz& rhs) : 
    foo(rhs.foo) 
{ 
    std::cout << "In Baz::Baz(const Baz&)" << std::endl; 
} 

Получаем:

 
In Foo::Foo() 
In Bar::Bar() 
In Baz::Baz() 
Copying... 
In Foo::Foo(const Foo&) 
In Bar::Bar() 
In Baz::Baz(const Baz&) 

Как вы можете видеть, как только вы явно объявить копию-конструктор вы отвечаете за копирование всех членов класса; это ваш конструктор.

Это относится ко всем конструкторам, включая конструкторы перемещения.

+0

Что делать, если элемент является необработанным указателем (например, void *) или int, double и т. Д. - будет ли пользовательский конструктор копирования присвоить 0 их перед входом {если пользователь не присваивает ничего этим членам в списке инициализации конструктора копирования? –

+0

@SergeRogatch: Если вы не инициализируете его явно, значение не указывается как обычная неинициализированная переменная, а чтение - неопределенное поведение. Вы должны явно инициализировать указатели на null, ints до 0 и т. Д. – GManNickG

2

Да. Ctors - ctors.

+0

+1, вы избили меня на 2 секунды. :) –

+1

-1: Что означает «Да» как ответ на вопрос, содержащий «или»? – mmmmmmmm

+1

rstevens, вопрос был отредактирован вскоре после того, как Чарли ответил. Чарли отлично ответил на исходный вопрос. Тем не менее, я отредактировал свой ответ ниже, и я думаю, что он достаточно хорош :) – GManNickG

2

Для любой переменной-члена, имеющей конструктор по умолчанию, который используется по умолчанию, вызывается, если вы явно не добавили какой-либо другой вызов конструктора для этой переменной-члена в список инициализации.

0

Когда компилятор предоставляет код по умолчанию, что, по вашему мнению, делает компилятор для переменных-членов? Это копии конструкций это.

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

+0

-1 извините. Предоставляемая компилятором копия по умолчанию ctor * будет * копировать каждого члена, используя собственную копию этого члена ctor (которая является побитовой копией в случае примитивных типов). –

+0

Да, но я говорю то же самое! * Default Initilalizes * означает копирование через член-член. – Abhay

+0

Я вижу, что вы говорите, но на самом деле термин «инициализации по умолчанию» имеет конкретное, четко определенное значение в стандарте C++, которое должно инициализировать объект с использованием значения по умолчанию типа (ну, это немного сложнее, но в любом случае ...) Итак, ваше описание немного вводит в заблуждение. –

1

Нет ничего волшебного в конструкторе копирования, кроме того, что компилятор добавит его в случае необходимости. Но в том, как он работает, нет ничего особенного - если вы явно не говорите «использовать такой-то и такой конструктор», он будет использовать значение по умолчанию.

1

Не в VC9. Не уверен в других.

// compiled as: cl /EHsc contest.cpp 
// 
// Output was: 
// Child1() 
// ----- 
// Child1() 
// Child2() 
// Parent() 
// ----- 
// Child1(Child1&) 
// Child2() 
// Parent(Parent&) 

#include <cstdio> 

class Child1 { 
    int x; 
public: 
    static Child1 DEFAULT; 

    Child1(){ 
     x = 0; 
     printf("Child1()\n"); 
    } 

    Child1(Child1 &other){ 
     x = other.x; 
     printf("Child1(Child1&)\n"); 
    } 
}; 

Child1 Child1::DEFAULT; 

class Child2 { 
    int x; 
public: 
    Child2(){ 
     x = 0; 
     printf("Child2()\n"); 
    } 

    Child2(Child2 &other){ 
     x = other.x; 
     printf("Child2(Child2&)\n"); 
    } 
}; 

class Parent { 
    int x; 
    Child1 c1; 
    Child2 c2; 

public: 
    Parent(){ 
     printf("Parent()\n"); 
    } 

    Parent(Parent &other) : c1(Child1::DEFAULT) { 
     printf("Parent(Parent&)\n"); 
    } 
}; 

int main(){ 
    printf("-----\n"); 
    Parent p1; 
    printf("-----\n"); 
    Parent p2(p1); 

    return 0; 
} 
+0

И началось это? –

2

Для получения дополнительной информации см: Is there an implicit default constructor in C++?

Short:

  • компилятор "Конструктор по умолчанию": используется конструктор по умолчанию для каждого элемента.
  • Компилятор Сгенерированный «Copy Constructor»: использует конструктор копирования каждого элемента.
  • Компилятор, сгенерированный «Оператор присваивания»: использует оператор присваивания для каждого элемента.
1

В зависимости от того, как инициируется конструктор базового вызова, конструкторы элемента будут называться одинаковым образом. Например, давайте начнем с:

struct ABC{ 
    int a; 
    ABC() : a(0) { printf("Default Constructor Called %d\n", a); }; 

    ABC(ABC & other) 
    { 
     a=other.a; 
     printf("Copy constructor Called %d \n" , a) ; 
    }; 
}; 

struct ABCDaddy{ 
    ABC abcchild; 
}; 

Вы можете сделать эти тесты:

printf("\n\nTest two, where ABC is a member of another structure\n"); 
ABCDaddy aD; 
aD.abcchild.a=2; 

printf("\n Test: ABCDaddy bD=aD; \n"); 
ABCDaddy bD=aD; // Does call the copy constructor of the members of the structure ABCDaddy (ie. the copy constructor of ABC is called) 

printf("\n Test: ABCDaddy cD(aD); \n"); 
ABCDaddy cD(aD); // Does call the copy constructor of the members of the structure ABCDaddy (ie. the copy constructor of ABC is called) 

printf("\n Test: ABCDaddy eD; eD=aD; \n"); 
ABCDaddy eD; 
eD=aD;   // Does NOT call the copy constructor of the members of the structure ABCDaddy (ie. the copy constructor of ABC is not called) 

Выход:

Default Constructor Called 0 

Test: ABCDaddy bD=aD; 
Copy constructor Called 2 

Test: ABCDaddy cD(aD); 
Copy constructor Called 2 

Test: ABCDaddy eD; eD=aD; 
Default Constructor Called 0 

Наслаждайтесь.

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