miércoles, 17 de septiembre de 2014

Apuntes de C++: Sobrecarga de funciones, constructores de copias y argumentos implícitos

Buenas a todos!
El siguiente post, continua con los apuntes sobre C++, esta vez resumo un poco el tema de la sobrecarga de funciones contructoras, los constructores de copias y los argumentos implícitos. Finalizo con algo curioso, obtener punteros que apunten a funciones sobrecargadas.

Las funciones constructoras de clase se pueden sobrecargar, pero las funciones destructoras no.


class Persona{
    int x;
public:
    Persona(){ x=0; }       //Constructor sin inicializador
    Persona(int n){ x=n; }  //Constructor con inicializador
};

En el código anterior tenemos la función constructora sobrecargada.
Sin la versión de constructor sin inicializador, no podría inicializarse un array dinámico, y se generaría un error en tiempo de compilación.

Persona *persona;
persona = new Persona[20];

Con el constructor sin inicializador el array dinámico persona, contiene 20 objetos de tipo persona, con x = 0.

Cuando se pasa un objeto a una función o esta lo devuelve pueden presentarse dificultades, ya que automáticamente se generan copias del objeto.

Al pasar un objeto a una función se realiza una copia bit a bit de ese objeto. Hay cosas que no deseamos que sean idénticas en la copia, como por ejemplo si el objeto original apunta a la memoria asignada por un puntero, la copia apuntará a la misma dirección de memoria, y la copia podría alterar la memoria original.

Cuando una función devuelve un objeto, normalmente el compilador generará un objeto temporal que mantiene una copia del valor devuelto por la función. Esta acción es automática y no controlable.
Este objeto desaparece al devolver su valor y al desaparecer llama a su función destructora.

Para evitar estos problemas se puede definir un "constructor de copias", un tipo especial de función constructora sobrecargada.

Situaciones en las que se aplica un constructor de copias

Los constructores de copias sólo se aplican a situaciones de inicialización, no de asignación.
Hay tres situaciones de inicialización típicas:
- Se emplea un objeto para inicializar otro en una declaración.
myclass x = y;
- Se pasa un objeto como parámetro a una función.
funcionX(y);
- Se crea un objeto temporal al devolver un objeto por una función.
y = funcionX();

class Persona{
    int x;
public:
    Persona(){ x=0; }       //Constructor sin inicializador
    Persona(int n){ x=n; }  //Constructor con inicializador
    Persona(const Persona &obj){…}//Constructor de copias
};

Argumentos implícitos

Usar argumentos implícitos es una forma abreviada de sobrecarga de funciones.
void f(int a = 0, int b = 0);
La función anterior emplea como argumentos implícitos los parámetros a y b.
Este tipo de declaración permite llamar a la función f de las siguientes formas:

f();    //a=0, b=0
f(5);   //a=5, b=0
f(5,2); //a=5, b=2

No hay forma de dar valor por defecto a 'a' y especificar 'b'.
Los argumentos implícitos deben ser constantes o variables globales.

Búsqueda de la dirección de una función sobrecargada

Igual que en C es posible asignar la dirección de una función a un puntero y acceder a la misma a través del puntero:

p = zap;  //donde tenemos zap();

Para obtener la dirección de una función sobrecargada, es el modo de declarar el puntero el que determina la dirección de la función sobrecargada.

void space(int count);
void space(int count, char ch);
main(){
    void (*fp1)(int);   //puntero a una función void con un parámetro int
    void (*fp2)(int)(char);
    
    fp1 = space;    //void space(int count);
    fp2 = space;    //void space(int count, char ch);
    
    fp1(22);
    fp2(30, 'x');
}


En el siguiente post, continuaré con la sobrecarga de operadores.
Un saludo a todos!


No hay comentarios:

Publicar un comentario