Pergunta

Eu sei que o compilador, por vezes, fornece um construtor de cópia padrão, se você não implementar-se. Estou confuso sobre o que exatamente esse construtor faz. Se eu tiver uma classe que contém outros objetos, nenhuma das quais tem um construtor de cópia declarou, qual será o comportamento ser? Por exemplo, uma classe como este:

class Foo {
  Bar bar;
};

class Bar {
  int i;
  Baz baz;
};

class Baz {
  int j;
};

Agora, se eu fizer isso:

Foo f1;
Foo f2(f1);

Qual será o construtor de cópia padrão fazer? Será que o construtor de cópia gerado pelo compilador em Foo chamar o construtor gerado pelo compilador em Bar para copiar bar, que irá chamar o construtor de cópia gerado pelo compilador em Baz?

Foi útil?

Solução

Foo f1;
Foo f2(f1);

Sim, isso vai fazer o que você espera que ele:
copiar os f2 construtor Foo :: Foo (Foo const &) é chamado.
Esta cópia constrói sua classe base e, em seguida, cada membro (de forma recursiva)

Se você definir uma classe como esta:

class X: public Y
{
    private:
        int     m_a;
        char*   m_b;
        Z       m_c;
};

Os seguintes métodos será definido pelo seu compilador.

  • Construtor (default) (2 versões)
  • Construtor (cópia)
  • Destructor (padrão)
  • Operador de atribuição

Construtor: Padrão:

Na verdade, existem dois construtores padrão.
Um é usado para zero-initialization enquanto o outro é usado para value-initialization. O usada depende se você usar () durante a inicialização ou não.

// Zero-Initialization compiler generated constructor
X::X()
    :Y()                // Calls the base constructor
                        //     If this is compiler generated use 
                        //     the `Zero-Initialization version'
    ,m_a(0)             // Default construction of basic PODS zeros them
    ,m_b(0)             // 
    m_c()               // Calls the default constructor of Z
                        //     If this is compiler generated use 
                        //     the `Zero-Initialization version'
{
}

// Value-Initialization compiler generated constructor
X::X()
    :Y()                // Calls the base constructor
                        //     If this is compiler generated use 
                        //     the `Value-Initialization version'
    //,m_a()            // Default construction of basic PODS does nothing
    //,m_b()            // The values are un-initialized.
    m_c()               // Calls the default constructor of Z
                        //     If this is compiler generated use 
                        //     the `Value-Initialization version'
{
}

Notas: Se a classe base ou quaisquer membros não tem um construtor padrão visível válido, então o construtor padrão não pode ser gerado. Este não é um erro a menos que suas tentativas de código para usar o construtor padrão (então somente um erro de tempo de compilação).

Construtor (cópia)

X::X(X const& copy)
    :Y(copy)            // Calls the base copy constructor
    ,m_a(copy.m_a)      // Calls each members copy constructor
    ,m_b(copy.m_b)
    ,m_c(copy.m_c)
{}

Notas: Se a classe base ou quaisquer membros não têm um construtor de cópia visível válido, então o construtor de cópia não pode ser gerado. Este não é um erro a menos que suas tentativas de código para usar o construtor de cópia (então somente um erro de tempo de compilação).

Atribuição Operador

X& operator=(X const& copy)
{
    Y::operator=(copy); // Calls the base assignment operator
    m_a = copy.m_a;     // Calls each members assignment operator
    m_b = copy.m_b;
    m_c = copy.m_c;

    return *this;
}

Notas: Se a classe base ou quaisquer membros não têm um operador de atribuição viável válido, então o operador de atribuição não pode ser gerado. Este não é um erro a menos que suas tentativas de código para usar o operador de atribuição (então somente um erro de tempo de compilação).

Destructor

X::~X()
{
                        // First runs the destructor code
}
    // This is psudo code.
    // But the equiv of this code happens in every destructor
    m_c.~Z();           // Calls the destructor for each member
    // m_b              // PODs and pointers destructors do nothing
    // m_a          
    ~Y();               // Call the base class destructor
  • Se qualquer construtor (incluindo cópia) é declarado, em seguida, o construtor padrão não é implementada pelo compilador.
  • Se o construtor de cópia é declarado, em seguida, o compilador não irá gerar um.
  • Se o operador de atribuição é declarada, em seguida, o compilador não irá gerar um.
  • Se um destruidor é declarado o compilador não irá gerar um.

Olhando para o código seguintes construtores de cópia são gerados:

Foo::Foo(Foo const& copy)
    :bar(copy.bar)
{}

Bar::Bar(Bar const& copy)
    :i(copy.i)
    ,baz(copy.baz)
{}

Baz::Baz(Baz const& copy)
    :j(copy.j)
{}

Outras dicas

O compilador fornece um construtor de cópia a menos que você declarar (nota: não definir ) um você mesmo. O construtor de cópia gerado pelo compilador simplesmente chama o construtor de cópia de cada membro da classe (e de cada classe base).

O mesmo é verdade para o operador de atribuição e o destruidor, BTW. É diferente para o construtor padrão, porém: que é fornecido pelo compilador somente se você não declarar qualquer outro construtor si mesmo.

Sim, a cópia do construtor executa gerados pelo compilador uma cópia membro-wise, na ordem em que os membros são declarados na classe que contém. Se qualquer um dos tipos de membro não se oferecem um construtor de cópia, o candidato a cópia construtor da classe que contém não pode ser gerado. Pode ainda ser possível escrever um manualmente, se você pode decidir sobre alguns meios adequados para inicializar o valor do membro que não pode ser construído-copy -. Talvez usando um de seus outros construtores

A C ++ construtor de cópia padrão cria um rasa copiar. Uma cópia superficial não irá criar novas cópias de objetos que o objeto original pode referência; os antigos e os novos objetos simplesmente contêm ponteiros distintas para o mesmo local de memória.

O compilador irá gerar os construtores necessários para você.

No entanto, assim que você definir uma cópia construtor mesmo, o compilador desiste gerando qualquer coisa para essa classe e vai dar e de erro se você não tem os construtores adequados definidos.

Usando o seu exemplo:

class Baz {
    Baz(const Baz& b) {}
    int j;
};
class Bar {
    int i;
    Baz baz;
};
class Foo {
    Bar bar;
};
Não

Tentando padrão instanciar ou copiar-construção Foo irá lançar um erro desde Baz é copiar-construível eo compilador não pode gerar o padrão e copiar constroctor para Foo.

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