Pergunta

Eu sei que se você deixar um membro de uma lista de inicialização em um construtor no-arg, o construtor padrão desse membro será chamado.

Do copiar construtores da mesma forma chamar o construtor de cópia dos membros, ou eles também chamar o construtor padrão?

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()?
}
Foi útil?

Solução

construtores de cópia explicitamente definidos não chamar construtores de cópia para os membros.

Quando você entra no corpo de um construtor, cada membro dessa classe será inicializada. Isto é, quando você começa a { você é garantido que todos os seus membros foram inicializados.

A menos que especificado, os membros estão na ordem em que aparecem na classe. Inicializado-default (E se eles não podem ser, o programa está mal-formado.) Então, se você definir o seu próprio construtor de cópia, é agora até você para chamar qualquer construtores de cópia membro como desejado.

Aqui é um pequeno programa que você pode copiar e colar em algum lugar e mexer com:

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

Como está, este impressões:

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

Note que é os membros da Baz-inicialização padrão.

Ao comentar o construtor de cópia explícita, como:

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

A saída será a seguinte:

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

Ele chama o copy-construtor em ambos.

E se reintroduzir construtor de cópia de Baz e explicitamente copiar um único membro:

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

Recebemos:

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

Como você pode ver, uma vez que você declarar explicitamente uma cópia construtor você são responsáveis ??pela cópia de todos os membros da classe; é o seu construtor agora.

Isto é válido para todos os construtores, incluindo construtores movimento.

Outras dicas

Sim. Ctors são ctors.

Para qualquer variável de membro ter um construtor padrão que construtor padrão é invocado, se não tiver adicionado explicitamente qualquer outra chamada do construtor dessa variável de membro na lista de inicialização.

Para mais detalhes ver: Existe um padrão implícito construtor em C ++?

curta:

  • Compiler Gerado "Default Construtor":. Usa o construtor padrão de cada membro
  • Compiler Gerado "Construtor de cópia": usa o construtor de cópia de cada membro.
  • Compiler Gerado "Atribuição Operador":. Usa o operador de atribuição de cada membro

Não há nada mágico sobre um construtor de cópia, além de que o compilador irá adicioná-lo em caso necessário. Mas em como ele realmente funciona, não há nada de especial -. Se você não dizer explicitamente "usar tal e tal construtor", ele vai usar o padrão

Não em VC9. Não tenho certeza sobre os outros.

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

Dependendo de como o construtor chamada base é iniciado, construtores do membro será chamado da mesma maneira. Por exemplo, vamos começar com:

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

Você pode fazer estes testes:

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)

Output:

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

Aproveite.

Quando o compilador fornece a cctor padrão, o que você acha que o compilador faz para as variáveis ??de membro? É copiar construções -lo.

Na mesma linha, se o cctor é definida pelo usuário, e se deixa de fora alguns membros, os membros não pode ser deixado não inicializado. invariantes de classe são estabelecidas durante a construção e têm de ser constantemente mantido. Assim, o compilador faz isso para você.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top