Asi funcionan los punteros. Son guardadores de las direcciones de memoria de los objetos.
El operador * y el operador -> no hacen mas que visitar las direcciones de memoria, por lo que cuando haces una copia de los punteros, solo haces copia de las direcciones, no de los objetos.
Por la misma razon, cuando modificas usando el operador -> estas visitando el mismo objeto para los 2 punteros.
Tener 2 punteros apuntando al mismo objeto se llama "alias" y esto que te ocurre es indicador de lo que ya te he explicado.
Posible solucion: Crea un constructor de copia y usalo en vez de hacer una asignacion en las lineas 69 y 70.
EL constructor de copia es un nuevo constructor que recibe un objeto del mismo tipo que la clase que estas creando.
Finalmene, despues de implementar el constructor de copia y reemplazar esas 2 lineas, tu codigo se veria:
persona *p3 = new persona(c->devuelve(0));
Sin ningun otro cambio necesario, deberia funcionar.
Una convencion que no estas usando es nombrar las clases con mayuscula inicial, intenta seguirlo para hacer mas facil a otros leer tu codigo.