Cópia superficial e cópia profunda
Na classe Circle, exemplo do construtor de cópia explicado na seção anterior, a estratégia de cópia é consistente com a estratégia padrão do sistema, ou seja, os membros do objeto original são copiados para os membros correspondentes do novo objeto em sequência. Nesse caso, por que ainda queremos defini-lo você mesmo? A razão é que simplesmente inicializar todas as situações desta forma simples levará inevitavelmente a problemas em diferentes situações.
Por exemplo, na classe Circle agora, se um membro ponteiro for adicionado à variável de membro e a memória precisar ser alocada dinamicamente durante a inicialização, haverá um enorme risco de segurança. O código é o seguinte:
/************************************//Des: programa de suporte ao tutorial C++ //Autor: Huang //Direitos autorais: www.dotcpp.com//Data:2017/8/26****************************** ** ******/#include<iostream>#include<Cstring>usingnamespacestd;#definePI3.1415classCircle{private:doubleR;char*str;public:Circle(doubleR,char*str);~Circle(); );doublegirth();};Circle::~Circle(){delete[]str;}Circle::Circle(doubleR,char*str){cout<<Constructor<<endl;this->R=R ;this ->str=newchar[strlen(str)+1];strcpy(this->str,str);cout<<this->R<<<<this->str<<endl;}doubleCircle::area () {returnPI*R*R;}doubleCircle::girth(){return2*PI*R;}intmain(){CircleA(5,NO.1Oldclass);CircleB(A);return0;}
Para verificar, na classe Circle, adicionamos um membro ponteiro e o inicializamos no construtor sem um construtor de cópia customizado. Então, na função principal, a frase Circle B(A); atribui o objeto A ao objeto B e chama o construtor de cópia gerado padrão. Após a execução, o programa relata um erro conforme mostrado abaixo:
A razão real é que o construtor de cópia padrão executa apenas atribuição de dados e não pode abrir espaço de memória para ponteiros, o que equivale ao código:
Isto->str=str;
Então, essencialmente, dois ponteiros apontam para um pedaço de espaço de heap. Foi contra a nossa intenção original. Então, ao final do programa, quando os dois objetos forem reciclados, seus próprios destruidores serão chamados para liberar esse espaço de memória. Como os dois objetos precisam ser chamados duas vezes, ou seja, deletados duas vezes, ocorrerá um erro!
Portanto, quando há um tipo de ponteiro na classe, confiar no método construtor de cópia padrão não pode mais atender às nossas necessidades. Um construtor de cópia específico deve ser definido, que pode não apenas copiar dados, mas também alocar espaço de memória para os membros. para obter uma cópia real, também chamada de cópia profunda, este é o construtor de cópia profunda .
Implementação do construtor de cópia profunda:
#include<iostream>#include<Cstring>usingnamespacestd;#definePI3.1415classCircle{private:doubleR;char*str;public:Circle(doubleR,char*str);Circle(Circle&A);~Circle();doublerea(); doublegirth();};Circle::~Circle(){delete[]str;cout<<CallDestructor<<endl;}Circle::Circle(Circle&A){cout<<CopyConstructor<<endl;this->R=AR ;this->str=newchar[strlen(A.str)+1];strcpy(this->str,A.str);}Circle::Circle(doubleR,char*str){cout<<Construtor<<endl ;this->R=R;this->str=newchar[strlen(str)+1];strcpy(this->str,str);}doubleCircle::area(){returnPI*R*R;}doubleCircle: :girth(){return2*PI*R;}intmain(){CircleA(5,NO.1Oldclass);CircleB(A);return0;}
O princípio de implementação é semelhante ao construtor com parâmetros. Espaço de memória suficiente é aberto antes da atribuição para realmente completar a cópia. Esta é a chamada "cópia profunda". Por favor, entenda e experimente no computador!