Explicación de C++ Virtual / Pure Virtual


¿Qué significa exactamente si una función se define como virtual y es lo mismo que virtual puro?

 293
Author: Trilarion, 2009-08-20

12 answers

Desde La función virtual de Wikipedia ...

Una función virtual o método virtual es una función o método cuyo comportamiento puede ser anulado dentro de una clase hereditaria por una función con la misma firma

Considerando..

Una función virtual pura o método virtual puro es una función virtual que debe ser implementada por una clase derivada que no es abstracta" - Wikipedia

Por lo tanto, la función virtual se puede sobrescribir y lo virtual puro debe ser implementado.

 292
Author: Diego Dias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-17 06:01:36

Me gustaría comentar la definición de Wikipedia de virtual, como se repite por varios aquí. [En el momento en que se escribió esta respuesta,] Wikipedia definió un método virtual como uno que puede ser anulado en subclases. [Afortunadamente, Wikipedia ha sido editada desde entonces, y ahora explica esto correctamente.] Eso es incorrecto: cualquier método, no solo los virtuales, puede ser anulado en subclases. Lo que virtual hace es darle polimorfismo, es decir, la capacidad de seleccionar en tiempo de ejecución los más derivados reemplazo de un método.

Considere el siguiente código:

#include <iostream>
using namespace std;

class Base {
public:
    void NonVirtual() {
        cout << "Base NonVirtual called.\n";
    }
    virtual void Virtual() {
        cout << "Base Virtual called.\n";
    }
};
class Derived : public Base {
public:
    void NonVirtual() {
        cout << "Derived NonVirtual called.\n";
    }
    void Virtual() {
        cout << "Derived Virtual called.\n";
    }
};

int main() {
    Base* bBase = new Base();
    Base* bDerived = new Derived();

    bBase->NonVirtual();
    bBase->Virtual();
    bDerived->NonVirtual();
    bDerived->Virtual();
}

¿Cuál es la salida de este programa?

Base NonVirtual called.
Base Virtual called.
Base NonVirtual called.
Derived Virtual called.

Derived anula cada método de Base: no solo el virtual, sino también el no virtual.

Vemos que cuando se tiene una Base-pointer-to-Derived (bDerived), llamar llamadas no virtuales a la implementación de la clase Base. Esto se resuelve en tiempo de compilación: el compilador ve que bDerived es una Base*, que NonVirtual no es virtual, por lo que hace la resolución en la base de la clase.

Sin embargo, la llamada Virtual llama a la implementación de la clase Derivada. Debido a la palabra clave virtual, la selección del método ocurre en tiempo de ejecución, no en tiempo de compilación. Lo que sucede aquí en tiempo de compilación es que el compilador ve que esto es una Base*, y que está llamando a un método virtual, por lo que inserta una llamada a la vtable en lugar de la clase Base. Esta vtable se crea una instancia en tiempo de ejecución, de ahí la resolución en tiempo de ejecución de la anulación más derivada.

I espero que esto no haya sido muy confuso. En resumen, cualquier método puede ser anulado, pero solo los métodos virtuales le dan polimorfismo, es decir, la selección en tiempo de ejecución de la anulación más derivada. En la práctica, sin embargo, anular un método no virtual se considera una mala práctica y rara vez se usa, por lo que muchas personas (incluido quien escribió ese artículo de Wikipedia) piensan que solo los métodos virtuales pueden ser anulados.

 178
Author: Asik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-03 19:15:46

La palabra clave virtual le da a C++ su capacidad de soportar polimorfismo. Cuando usted tiene un puntero a un objeto de alguna clase como:

class Animal
{
  public:
    virtual int GetNumberOfLegs() = 0;
};

class Duck : public Animal
{
  public:
     int GetNumberOfLegs() { return 2; }
};

class Horse : public Animal
{
  public:
     int GetNumberOfLegs() { return 4; }
};

void SomeFunction(Animal * pAnimal)
{
  cout << pAnimal->GetNumberOfLegs();
}

En este ejemplo (tonto), la función GetNumberOfLegs() devuelve el número apropiado basado en la clase del objeto para el que se llama.

Ahora, considere la función 'someFunction'. No le importa qué tipo de objeto animal se le pase, siempre y cuando se derive de un Animal. El compilador lanzará automáticamente cualquier Clase derivada de un animal, ya que es una clase base.

Si hacemos esto:

Duck d;
SomeFunction(&d);

Daría salida a '2'. Si hacemos esto:

Horse h;
SomeFunction(&h);

Daría salida a '4'. No podemos hacer esto:

Animal a;
SomeFunction(&a);

Porque no se compilará debido a que la función virtual GetNumberOfLegs() es pura, lo que significa que debe implementarse derivando clases (subclases).

Las funciones virtuales puras se utilizan principalmente para definir:

A) clases abstractas

Estas son clases base donde tienes que derive de ellos y luego implemente las funciones virtuales puras.

B) interfaces

Estas son clases 'vacías' donde todas las funciones son virtuales puras y por lo tanto tienes que derivar y luego implementar todas las funciones.

 109
Author: JBRWilkinson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-25 00:29:41

En una clase C++, virtual es la palabra clave que designa que, un método puede ser sobreescrito (es decir, implementado por) una subclase. Por ejemplo:

class Shape 
{
  public:
    Shape();
    virtual ~Shape();

    std::string getName() // not overridable
    {
      return m_name;
    }

    void setName( const std::string& name ) // not overridable
    {
      m_name = name;
    }

  protected:
    virtual void initShape() // overridable
    {
      setName("Generic Shape");
    }

  private:
    std::string m_name;
};

En este caso una subclase puede anular la función the initShape para hacer algún trabajo especializado:

class Square : public Shape
{
  public: 
    Square();
    virtual ~Square();

  protected:
    virtual void initShape() // override the Shape::initShape function
    {
      setName("Square");
    }
}

El término virtual puro se refiere a las funciones virtuales que necesitan ser implementadas por una subclase y no han sido implementadas por la clase base. Se designa un método como virtual puro mediante el uso de la virtual palabra clave y la adición de una =0 al final de la declaración del método.

Entonces, si quisieras hacer que Shape::initShape sea virtual puro, harías lo siguiente:

class Shape 
{
 ...
    virtual void initShape() = 0; // pure virtual method
 ... 
};

Al agregar un método virtual puro a su clase, convierte a la clase en una clase base abstracta lo cual es muy útil para separar las interfaces de la implementación.

 30
Author: Nick Haddad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-06 10:07:13

"Virtual" significa que el método puede ser sobrescrito en subclases, pero tiene una implementación directamente llamable en la clase base. "Virtual puro" significa que es un método virtual sin implementación directamente llamable. Tal método debe ser sobrescrito al menos una vez en la jerarquía de herencia if si una clase tiene métodos virtuales no implementados, los objetos de esa clase no pueden ser construidos y la compilación fallará.

@quark señala que los métodos puramente virtuales puede tener una implementación, pero como los métodos pure-virtual deben ser sobrescritos, la implementación predeterminada no se puede llamar directamente. Aquí hay un ejemplo de un método virtual puro con un valor predeterminado:

#include <cstdio>

class A {
public:
    virtual void Hello() = 0;
};

void A::Hello() {
    printf("A::Hello\n");
}

class B : public A {
public:
    void Hello() {
        printf("B::Hello\n");
        A::Hello();
    }
};

int main() {
    /* Prints:
           B::Hello
           A::Hello
    */
    B b;
    b.Hello();
    return 0;
}

Según los comentarios, si la compilación fallará o no es específica del compilador. En GCC 4.3.3 al menos, no compilará:

class A {
public:
    virtual void Hello() = 0;
};

int main()
{
    A a;
    return 0;
}

Salida:

$ g++ -c virt.cpp 
virt.cpp: In function ‘int main()’:
virt.cpp:8: error: cannot declare variable ‘a’ to be of abstract type ‘A’
virt.cpp:1: note:   because the following virtual functions are pure within ‘A’:
virt.cpp:3: note:   virtual void A::Hello()
 14
Author: John Millikin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-20 17:12:29

¿Cómo funciona la palabra clave virtual?

Asumir que el Hombre es una clase base, Indio se deriva del hombre.

Class Man
{
 public: 
   virtual void do_work()
   {}
}

Class Indian : public Man
{
 public: 
   void do_work()
   {}
}

Declarar do_work() como virtual simplemente significa: qué do_work() llamar se determinará SOLO en tiempo de ejecución.

Supongamos que lo hago,

Man *man;
man = new Indian();
man->do_work(); // Indian's do work is only called.

Si virtual no se utiliza, el mismo se determina estáticamente o estáticamente enlazado por el compilador, dependiendo de qué objeto está llamando. Así que si un objeto de Man llama a do_work (), se llama a do_work () DE Man AUNQUE APUNTA A UN OBJETO INDIO

Creo que la respuesta más votada es engañosa: Cualquier método, ya sea virtual o no, puede tener una implementación anulada en la clase derivada. Con referencia específica a C++ , la diferencia correcta es el enlace en tiempo de ejecución (cuando se usa virtual) y el enlace en tiempo de compilación (cuando no se usa virtual pero se anula un método y un puntero base apunta a un objeto derivado) de las funciones asociadas.

Parece haber otro comentario engañoso que dice:

"Justin,' virtual puro ' es solo un término (no una palabra clave, ver mi respuesta abajo) usado para significar " esta función no puede ser implementada por la base clase."

¡ESTO ESTÁ MAL! Las funciones puramente virtuales también pueden tener un cuerpo Y SE PUEDEN IMPLEMENTAR! ¡La verdad es que la función virtual pura de una clase abstracta se puede llamar estáticamente! Dos muy buenos autores son Bjarne Stroustrup y Stan Lippman.... porque escribieron el idioma.

 9
Author: McMurdo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-24 19:13:59

Simula, C++ y C#, que utilizan el enlace de métodos estáticos por defecto, el programador puede especificar que los métodos particulares deben usar el enlace dinámico etiquetándolos como virtuales. El enlace dinámico de métodos es fundamental para la programación orientada a objetos.

La programación orientada a objetos requiere tres conceptos fundamentales: encapsulación, herencia y enlace de método dinámico.

Encapsulation permite los detalles de implementación de un abstracción que debe esconderse detrás un interfaz simple.

Herencia permite que una nueva abstracción se defina como un extensión o refinamiento de algunos abstracción existente, obteniendo algunos o todas sus características automática.

Enlace de método dinámico permite que la nueva abstracción muestre su nuevo comportamiento incluso cuando se usa en un contexto eso espera la vieja abstracción.

 2
Author: PJT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-04 09:50:34

Los métodos virtuales SE pueden sobrescribir derivando clases, pero necesitan una implementación en la clase base (la que se sobrescribirá)

Los métodos virtuales puros no tienen implementación de la clase base. Necesitan ser definidos por clases derivadas. (Así que técnicamente invalidado no es el término correcto, porque no hay nada que invalidar).

Virtual corresponde al comportamiento predeterminado de java, cuando la clase derivada anula un método de la clase base.

Métodos virtuales puros corresponden al comportamiento de los métodos abstractos dentro de las clases abstractas. Y una clase que solo contiene métodos virtuales puros y constantes sería el cpp-pendant a una Interfaz.

 1
Author: johannes_lalala,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-23 22:48:50

Función Virtual pura

Pruebe este código

#include <iostream>
using namespace std;
class aClassWithPureVirtualFunction
{

public:

    virtual void sayHellow()=0;

};

class anotherClass:aClassWithPureVirtualFunction
{

public:

    void sayHellow()
    {

        cout<<"hellow World";
    }

};
int main()
{
    //aClassWithPureVirtualFunction virtualObject;
    /*
     This not possible to create object of a class that contain pure virtual function
    */
    anotherClass object;
    object.sayHellow();
}

En la clase Otra clase elimine la función sayHellow y ejecute el código. usted recibirá error!Porque cuando una clase contiene una función virtual pura, no se puede crear ningún objeto a partir de esa clase y se hereda entonces su clase derivada debe implementar esa función.

Función virtual

Intente otro código

#include <iostream>
using namespace std;
class aClassWithPureVirtualFunction
{

public:

    virtual void sayHellow()
    {
        cout<<"from base\n";
    }

};

class anotherClass:public aClassWithPureVirtualFunction
{

public:

    void sayHellow()
    {

        cout<<"from derived \n";
    }

};
int main()
{
    aClassWithPureVirtualFunction *baseObject=new aClassWithPureVirtualFunction;
    baseObject->sayHellow();///call base one

    baseObject=new anotherClass;
    baseObject->sayHellow();////call the derived one!

}

Aquí la función sayHellow está marcada como virtual en base class.It digamos el compilador que intenta buscar la función en clase derivada e implementar la función.Si no se encuentra, ejecute la base.Gracias

 0
Author: Tunvir Rahman Tusher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-28 15:32:17

"Una función virtual o método virtual es una función o método cuyo comportamiento puede ser anulado dentro de una clase hereditaria por una función con la misma firma" - wikipedia

Esta no es una buena explicación para las funciones virtuales. Porque, incluso si un miembro no es virtual, las clases heredadas pueden anularlo. Puedes intentarlo y verlo tú mismo.

La diferencia se muestra cuando una función toma una clase base como parámetro. Cuando se da una clase heredera como la entrada, que function utiliza la implementación de la clase base de la función anulada. Sin embargo, si esa función es virtual, utiliza la que está implementada en la clase derivada.

 0
Author: can,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-14 18:56:36
  • Las funciones virtuales deben tener una definición en la clase base y también en la clase derivada, pero no es necesario, por ejemplo toString() o toString() la función es virtual, por lo que puede proporcionar su propia implementación anulándola en la(s) clase (es) definida (s) por el usuario.

  • Las funciones virtuales se declaran y definen en clase normal.

  • La función virtual pura debe declararse terminando con "= 0 " y solo puede declararse en clase abstracta.

  • An clase abstracta tener una función virtual pura(s) no puede tener una definición(s) de que las funciones virtuales puras, lo que implica que la aplicación debe ser proporcionada en clase(s) que se deriven de esa clase abstracta.

 0
Author: Sohail xIN3N,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-26 07:28:26

Una función virtual es una función miembro que se declara en una clase base y que es redefinida por clase derivada. Las funciones virtuales son jerárquicas en orden de herencia. Cuando una clase derivada no anula una función virtual , se utiliza la función definida dentro de su clase base.

Una función virtual pura es aquella que no contiene ninguna definición relativa a la clase base. No tiene implementación en la clase base. Cualquier clase derivada debe anular esto función.

 0
Author: rashedcs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-07 03:52:24