Última actualización:2026-10-12
Funciones virtuales (virtual) en C++¶
Sobre el autor:¶
Cuenta pública personal:

1. Funciones virtuales y polimorfismo en tiempo de ejecución¶
Código correspondiente: emp.cpp
La llamada a una función virtual depende del tipo del objeto apuntado o referenciado, no del tipo del propio puntero o referencia.
2. vptr y vtable¶
3. Parámetros por defecto en funciones virtuales¶
Código correspondiente: default_arg.cpp
Los parámetros por defecto se enlazan estáticamente, mientras que las funciones virtuales se enlazan dinámicamente. El uso de un parámetro por defecto depende del tipo del propio puntero o referencia, no del tipo del objeto.
4. Qué se puede y qué no se puede¶
(1) ¿Puede una función estática declararse como virtual?
Hay dos razones principales:
Una función estática no puede declararse virtual, ni tampoco puede modificarse con las palabras clave const y volatile
La función miembro static no pertenece a ningún objeto de clase ni instancia de clase, de modo que añadirle virtual no tendría ningún sentido
Las funciones virtuales se apoyan en el vptr y el vtable. El vptr es un puntero que se crea en el constructor de la clase y solo puede accederse a él mediante el puntero this; las funciones miembro estáticas no tienen puntero this, por lo que no pueden acceder al vptr.
Código para estudiar: static_error.cpp
(2) ¿Puede un constructor ser una función virtual?
Un constructor no puede declararse virtual. Además, salvo inline|explicit, el constructor no admite ninguna otra palabra clave.
¿Por qué el constructor no puede ser una función virtual?
Aunque la tabla de funciones virtuales vtable se construye ya en la fase de compilación, el puntero a la tabla de funciones virtuales, vptr, no se genera hasta la fase de ejecución, al instanciar el objeto. Si la clase contiene funciones virtuales, el compilador añade código en el constructor para crear el vptr. Ahí está el problema: si el constructor fuera virtual, necesitaría el vptr para acceder al vtable, pero en ese momento el vptr aún no se ha generado. Por eso, el constructor no puede ser una función virtual.
Usamos funciones virtuales porque necesitamos ejecución polimórfica con información incompleta. El constructor, en cambio, sirve para inicializar la instancia, y el tipo de la instancia debe ser inequívoco. Por lo tanto, no hay ninguna necesidad de declarar el constructor como función virtual.
Código para estudiar:
(3) ¿Puede el destructor ser una función virtual?
El destructor puede declararse virtual. Si necesitamos eliminar mediante un puntero a la clase base un objeto de la clase derivada, el destructor debe declararse virtual. De hecho, siempre que una clase pueda ser heredada por otras, debería declararse un destructor virtual (aunque ese destructor no ejecute ninguna operación).
Código para estudiar:
(4) ¿Puede una función virtual ser privada?
- Si un puntero a la clase base apunta a un objeto de la clase derivada, se invoca la función del objeto de la clase derivada;
- int main() debe declararse friend de la clase Base, de lo contrario la compilación falla. El compilador da el error: ptr no puede acceder a la función privada. Por supuesto, si la clase base se declara public y la clase derivada private, el problema desaparece.
Código para estudiar:
(5) ¿Puede una función virtual ser inline?
Normalmente el compilador considera si conviene insertar (inline) las funciones miembro de una clase. Pero una función virtual invocada mediante puntero o referencia a la clase base no puede ser inline en ningún caso. Por supuesto, cuando la invocación se hace desde el objeto real, o cuando la llamada es estática, sí puede insertarse, y la llamada estática a un destructor virtual también se expandirá inline.
- Una función virtual puede ser una función inline; inline puede modificar a una función virtual, pero cuando la función virtual manifiesta polimorfismo no puede insertarse.
- inline es una sugerencia al compilador para que inserte en tiempo de compilación, mientras que el polimorfismo de la función virtual ocurre en tiempo de ejecución; el compilador no puede saber qué código se invocará en ejecución, por eso una función virtual no puede ser inline cuando manifiesta polimorfismo (en tiempo de ejecución).
inline virtualsolo puede insertarse cuando el compilador sabe de qué clase es el objeto invocado (por ejemploBase::who()), lo cual solo ocurre cuando el compilador tiene el objeto real y no un puntero o referencia al objeto.
Código para estudiar:
5. RTTI y dynamic_cast¶
RTTI (Run-Time Type Identification): gracias a la información de tipos en tiempo de ejecución, un programa puede usar un puntero o una referencia a la clase base para comprobar el tipo real de la clase derivada del objeto al que apuntan o refieren.
En la programación orientada a objetos, a veces necesitamos consultar en tiempo de ejecución si un objeto puede usarse como un determinado tipo polimórfico. De forma análoga al instanceof de Java y a los operadores as e is de C#, C++ ofrece la función dynamic_cast para la conversión dinámica. Frente a la conversión forzada al estilo de C y al reinterpret_cast de C++, dynamic_cast proporciona comprobación de seguridad de tipos: es una conversión basada en consulta de capacidades (Capability Query), por lo que para convertir entre tipos polimórficos es más recomendable usar dynamic_cast.
Código para estudiar:
6. Funciones virtuales puras y clases abstractas¶
Ver temas sobre funciones virtuales puras y clases abstractas
Temas relacionados¶
- Funciones virtuales puras y clases abstractas en C++ | C++那些事
- Aserciones assert en C++ | C++那些事
- Campos de bits en C++ | C++那些事
- Implementar el polimorfismo de C++ en lenguaje C | C++那些事
- const en C++: constantes y modificación | C++那些事
- La familia completa de const en C++ | C++那些事
- El operador de desreferencia * en C++ | C++那些事
- Inicialización y asignación en C++ | C++那些事
- Formas de devolver varios valores en C++ | C++那些事
- La palabra clave mutable en C++ | C++那些事