Cual es el sentido de las funciones virtuales puras?

Iniciado por digimikeh, 5 Octubre 2019, 17:59 PM

0 Miembros y 1 Visitante están viendo este tema.

digimikeh

Hola!

Hago esta pregunta desde la ignorancia, entiendo que virtual/override ayuda mucho a no tener que redefinir trozos de codigo de una función, sin embargo no entiendo cual es el fin de las funciones virtuales puras, es decir, no implementan nada, solo veo que ocupan un espacio en el archivo de cabecera, al fin y al cabo de todas formas tendrás que volver a declararlas y definirlas en las subclases como override...



class A{
protected:
    virtual void hacer_algo() = 0;     //Esto me parece que estuviera de más.....
    //otras cosas..

};



class B : public A{
protected:
    void hacer_algo() override;   //.... si aqui tengo que estar escribiendolo nuevamente.

};


Por qué no directamente?:


class A{
protected:
    //otras cosas
};



class B : public A{
protected:
    void hacer_algo();
};

Dungeons & dragons;
dragons.Attack();

vangodp

Voy a dar un caso a ver si lo entiendes. Imagina una clase ave, todas as aves vuelan, el gorrión, las palomas, etc, pero hay una ave que no vuela... ¿Sabes cual es? El pengüino. En todos los demás pájaros será mas o menos igual pero en pengüino, al llamarla, el pengüino no debería volar >_<.

Te eh dado el caso del pengüino en que casi todas las funciones son iguales, pero imagina una clase mamíferos con un método virtual puro "comunicar". Un perro ladra, un gato maúlla, y ciertamente los hay los que no hacen ruido,  pero de algún modo se comunican, depende del caso, creo que ese seria el mejor ejemplo.

digimikeh

Gracias por responder.

Aunque de todas formas con el ejemplo que me das (que es valido) aun no le hallo sentido a tener que escribir una linea (funcion virtual pura) mas en la super clase ya que siempre en las subclases la tendré que declarar (override) y definir...  Veo a las funciones puras como una interfaz mas que nada, ejemplo:


class Animal{
protected:
     virtual void emitir_sonido() const = 0;

};



class Canario : protected Animal{
protected:
     void emitir_sonido() override{ std::cout << "piop piop"; }
};



class Arana: protected Animal{
protected:
     //nada
};


No sería mejor esto?


class Animal{
protected:
     //nada
};



class Canario : protected Animal{
protected:
     void emitir_sonido(){ std::cout << "piop piop"; }
};



class Arana: protected Animal{
protected:
    //nada
};


De esta forma, de igual forma no necesito funcion virtual pura para hacer callar a la araña y para hacer cantar al canario...o no?
Dungeons & dragons;
dragons.Attack();

rub'n

#3
Cita de: digimikeh en  5 Octubre 2019, 17:59 PM
Hola!

Hago esta pregunta desde la ignorancia, entiendo que virtual/override ayuda mucho a no tener que redefinir trozos de codigo de una función, sin embargo no entiendo cual es el fin de las funciones virtuales puras, es decir, no implementan nada, solo veo que ocupan un espacio en el archivo de cabecera, al fin y al cabo de todas formas tendrás que volver a declararlas y definirlas en las subclases como override...



class A{
protected:
    virtual void hacer_algo() = 0;     //Esto me parece que estuviera de más.....
    //otras cosas..

};



class B : public A{
protected:
    void hacer_algo() override;   //.... si aqui tengo que estar escribiendolo nuevamente.

};


Por qué no directamente?:


class A{
protected:
    //otras cosas
};



class B : public A{
protected:
    void hacer_algo();
};



Dog, por ejemplo en java, el @Override se usa en herencia,  con subClases de clases abstractas e interfaces, el patrón template, hay un ejemplo donde, el método por ejemplo

Código (java) [Seleccionar]
abstract void pintar(String color);

Es invocado en la misma clase abstracta, pero por obligatoriedad debe ser declaro en la subClase y con @Override(aun sin tener nada dentro de su scope(alcance) llaves  Lmao), a simple vista pareciera que no hace nada(en dicha subClase), pero cuando la clase abstracta se ejecuta por medio de la subclase, este método pintar se invoca virtualmente por la JVM.




rubn0x52.com KNOWLEDGE  SHOULD BE FREE!!!
If you don't have time to read, you don't have the time (or the tools) to write, Simple as that. Stephen

K-YreX

Yo diría que las funciones virtuales puras lo que hacen es imponer condiciones al programador. Imagina que creas una clase <Animal> que no vas a instanciar directamente sino que la vas a usar de molde para crear otras clases hijas que hereden de <Animal>. Entonces en esta clase <Animal> deberías crear funciones virtuales puras como <comer()>, <relacionarse()>, etc. Lo que consigues al hacerlas virtuales puras es que cuando crees un tipo de animal concreto y éste herede de <Animal> te verás "obligado" a redefinir esas funciones virtuales puras.

Puedes verlo también de otra forma. Tú puedes crear una clase abstracta de la que heredarán otras clases pero resulta que las clases hijas no las vas a hacer tú, sino que lo harán diferentes programadores, pero para que todo funcione bien tú necesitas decir al resto de programadores que sus clases deben contener una serie de funciones sí o sí. Cómo lo haces? Creas esas funciones como virtuales puras en la clase abstracta.
En el mismo ejemplo de antes, tú dices a un grupo de personas que se inventen unos animales y que tengan las características que ellos quieran PERO que todos los animales deben emitir un ruido, el que sea. Pues creas una función virtual pura que sea <emitirRuido()> y cuando las demás personas hagan que sus clases hereden de <Animal> deberán hacer que cada clase implemente de alguna forma esa función <emitirRuido()>.

Esto yo por ejemplo lo vi bastante bien al aprender Java donde esto se usa en las interfaces porque Java no permite la herencia múltiple. No lo he usado más que en un par de códigos pequeños en forma de "apuntes" pero digamos que así es cómo yo lo entiendo. Puede que tenga otros usos o interpretaciones y quien las conozca puede corregirme. :-X
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

digimikeh

oh eso esta muy bueno, tiene mucho sentido el imponer reglas cuando hay mas programadores.

Gracias a todos por las respuestas.
Dungeons & dragons;
dragons.Attack();

Loretz

También:

Una función virtual pura convierte a la clase en una Clase Base Abstracta (una ABC - abstract base class), con la idea de separar la interfaz de la implementación.

Suponte que trabajas en una empresa que tiene toda una colección de clases a las que sus programadores deben obligatoriamente adscribir. Será una buena idea que se presenten como una "Interfaz" pura (una clase abstracta) y que si en algún momento se necesita modificar alguna parte de su implementación, ninguno de los quichicientos programas y progamitas que la usaron necesitarán ser recompilados.

Va un ejemplo de uso:
Código (cpp) [Seleccionar]
#include <iostream>
#include <string>

// Interfaz
class Empleado {
    //... todos lo que se pretende de un empleado abstracto
public:
    virtual std::string trabajar() = 0; // ya esto hace que la clase se abstracta.
    virtual void lamer_botas() {};
    virtual void ser_despedido() {};
    //...
};

// Un tipo de Empleado concreto:
//   - obligada a sobreescribir las funciones virtuales puras,
//   - se espera sobrescritas las otras virtuales
class Gerente : public Empleado {
    // ...
public:
    virtual std::string trabajar() override {
        return "Trabajen esclavos!\n";
    }

    // ...
};

void funcion_que_acepta_un_Empleado(Empleado& e) {
    std::cout << e.trabajar();
}

int main()
{
    //Empleado e; // Error: Empleado es una interfaz, no se puede crear un objeto de clase abstracta

    Gerente g; // Bien, este es un Empleado pero concreto.

    funcion_que_acepta_un_Empleado(g);  // esta funcion espera un Empleado como parametro.
}


Aquí la idea es que un Empleado es algo abstracto, una fantasía metafísica, inexistente en el mundo de las cosas. Pero se tienen funciones que trabajan con Empleados pasados por parámentro, de modo que se le puede pasar cualquier objeto que sea un Empleado concreto (de una clase derivada de Empleado). De este modo tienes código que actúa sobre Empleados, código genérico (durante la ejecución se decidirá de qué tipo de Empleado se trata).

Luego se podrá crear más tipos de Empleados, si hiciera falta, o modificar cualquiera de las funciones expuestas en la interfaz, y nadie sufrirá.



vangodp

Mierd.... tuve media hora leyendo para decir lo que ha dicho YreX-DwX :laugh:¡Muy bien explicado! Debería haber esperado y así me ahoraba un buen tiempo yo también  :xD
Es correcto, hay creo 2 casos en los que es factible declarar una función como virtual pura según eh leido.


  • 1º Cuando no sea posible definir las funcionalidades en la clase madre. Tipo cuando tienes clases circulo, cuadrado, triangulo, etc, y que heredan de una clase madre como Shape(Forma), en esta clase shape una función como "getArea" no seria posible definir-la en la clase madre ya que se necesita "diferentes formas"(polmorfismo? :silbar:) para extraer el área de las figuras geométricas. Si fuera posible definir el funcionamiento de las subclases ya de entrada en la clase madre entonces no hace falta ser pura la función.

  • 2º Como ya comentó YreX-DwX... Sería para obligar a que se implemente en todas las subclases dicha función sea por el motivo que sea
YreX-DwX  ;-)

digimikeh

Dungeons & dragons;
dragons.Attack();