Document ID: /fineweb-2-swissfilter-quality_10-filterrobots/filtered/05326.jsonl.gz/37

Los punteros a tipos derivados son similares a aquellos a tipos base. Si suponemos que B_clase es el tipo base y que D_clase es el tipo derivado, cualquier puntero declarado a B_clase pude ser puntero a D_clase.
Por medio de p todos los elementos de D_ob heredados de B_ob son accesible. No obstante no es posible hacer una referencia a los elementos específicos de D_ob a través de p si no es mediante una conversión de tipo.
Considérese por ejemplo el siguiente programa en el que se define una clase fundamental llamada B_classe y una derivada D_classe. Esta última realiza una llamada automática de teléfono.
En este ejemplo el puntero p está definido como puntero a B_classe y por ello puede apuntar a un objeto de la clase derivada D_classe y ser utilizado para acceder a los elementos de la clase derivada definidos en la clase base. Sin embargo no puede acceder a los elementos de la clase derivada que están definidos en ella misma sin hacer un reconversión de tipo.
Esto explica por qué a visualizza_telefono() se accede por medio de dp, puntero a la clase derivada. Si se desea acceder a los elementos definidos de un tipo derivado con un putero de tipo fundamental, hay que convertir este último en un puntero a un tipo derivado. Por ejemplo la línea que sigue hace una llamada correcta a la función visualizza_telefono() definida en D_ob:
Los paréntesis extremos son necesarios para asociar la conversión a p y no al tipo que retorna visualizza_telefono(). Técnicamente hablando aunque esta conversión es correcta, es mejor evitarla para no generar confusión en el código del programa.
Un puntero a la clase base o fundamental puede apuntar también a una clase derivada. En cambio un puntero a la clase derivada no puede apuntar a la fundamental.
Hay que destacar además que las operaciones de incremento y decremento modifican el puntero respeto a su tipo fundamental. En consecuencia, cuando un puntero a una clase fundamental apunta a una clase derivada, no es cierto que cuando se incrementa o decrementa apunte al objeto sucesivo de la clase derivada. Operaciones de incremento o decremento del puntero a la clase derivada son por tanto consideradas incorrectas.
El hecho que un puntero a un tipo fundamental pueda ser utilizado para apuntar a cualquier objeto derivado de aquel tipo es de gran importancia en el C++, sobretodo considerando el modo en que este lenguaje realiza el polimorfismo.
El polimorfismo en fase de ejecución se consigue mediante el uso de tipos derivados y de funciones virtuales. En síntesis, una función virtual es una función declarada virtual en una clase fundamental y redefinida en una o más clases derivadas. La peculiaridad de estas funciones es que cuando se accede a ellas en clases derivadas por medio de un puntero a la clase fundamental, el C++ determina en la fase de ejecución del programa la dirección correcta de la función que debe de llamar según el objeto a donde apunte el puntero. Gracias a tal característica, apuntando a objetos diferentes se hacen llamadas a funciones virtuales diferentes (las cuales como es natural corresponden siembre a su objeto).
Una función se declara virtual en la clase base anteponiendo a la declaración la palabra llave virtual. Cuando una función virtual es redefinida en una clase derivada, no es necesario repetir la palabra llave virtual, aunque si se repite no se origina error.
Par ilustrar lo dicho véase el siguiente ejemplo:
La función chi() en la clase Base está declarada virtual. Esto significa que puede ser redefinida en una clase derivada. Tal función redefinida, tanto en el interior de prima_d como en el interior de prima_d como en el interior de seconda_d. En main() hay declaradas cuatro variables:
Al inicio del programa a p se le asigna la dirección de base_ogg y llama a la función chi(). Dado que chi() ha sido declarada como virtual, el C++ determina en fase de ejecución a qué versión de chi() se refiere el tipo de objeto apuntado por p. en este caso se trata de un objeto de tipo Base por lo que se ejecuta la versión de chi() declarada en Base. A p se le asigna la dirección de primo_ogg.
Como se ha dicho, se puede utilizar un puntero de la clase fundamental para hacer una referencia a cualquier clase derivada. Cuando se hace una nueva llamada a chi(), el C++ examina otra vez el tipo de objeto apuntado por p para determinar qué versión de chi() debe llamar.
Más adelante en el programa se asigna a p la dirección de prima_d y después sigue una llamada chi(). De nuevo el C++, en base a dicha asignación determina la función chi() a la que debe de llamar haciéndolo con la chi() definida en la clase prima_d. Analogamente cuando a p se le asigna la dirección secondo_ogg, una llamada a la función chi(), lo hace llamando a chi() de la clase seconda_d.
Hay que señalar que para llevar a cabo el polimorfismo en la fase de ejecución es indispensable acceder a las funciones virtuales por medio de un puntatore a la clase fundamental pues si bien es posible llamar explícitamente una función virtual utilizando el nombre del objeto, como se hace en los elementos función, el polimorfismo en fase de ejecución se consigue sólo accediendo a una función virtual por medio de un puntero a la clase fundamental.
La redefinición de una función virtual en una clase derivada es una forma particular de sobrecarga de funciones. Se prefiere no obstante no adoptar esta forma ya que esta manera de sobrecarga presenta varios límites. En la sobrecarga de una función normal el valor de retorno así como el número de parámetros puede diferir respecto a los de la clase fundamental. En cambio en el caso de las funciones virtuales el valor de retorno así como el número y el tipo de parámetros debe de coincidir con los de la clase fundamental ya que de no ser así dicha función pierde su característica de virtual. Se considera también erróneo que la función difiera sólo en el valor de retorno (resulta ambiguo de todas formas que una función difiere solo en el valor de retorno). Además una función virtual tiene que ser un elemento de la clase para la cal fue definida y no una función friend. No obstante una función virtual puede ser friend d otra clase. Por último las funciones virtuales pueden ser destructores pero no constructores.
Dada las diferencias y limitaciones entre la sobrecarga de funciones normales y de funciones virtuales, para describir la redefinición de una función virtual se recurre al término ovrerriding.
Siempre que una función es declarada virtual permanece así independientemente del nivel de derivación en el que se declaró virtual. Por ejemplo si seconda_d deriva de prima_d en lugar que de Base, como se muestra a continuación, chi() es siempre virtual y el programa ejecuta siempre la versión correcta.
Hay que tener presente que las características heredadas son jerárquicas. Por tanto, si seconda_d se deriva de prima_d en vez de Base, cuando se llama chi() en relación a un objeto de tipo soconda_d la versión de chi() que es ejecutada es aquella declarada en prima_d, que es la clase más próxima a la clase seconda_d.