Para convertir un puntero a un objeto de una clase a otra clase, tienes 3 casts posibles:
- static_cast: En el momento de compilar, comprueba si lo puede convertir. En tu caso, estás convirtiendo un A* a un B*. Como A* no hereda de B*, dará error. (Aunque sea un AB*, es una variable A* lo que estás convirtiendo a B*)
- dynamic_cast: En vez de comprobar a la hora de compilar, lo hace mientras se ejecuta. Este va a comprobar si se puede hacer el cast, y si no se puede, lanzará una excepción (En este caso se puede, y no tendrás problema).
- reinterpret_cast: Este cast no hace comprobaciones. Se limita a tratar la secuencia de bytes del objeto como si de otro objeto se tratase. En este caso, eso no es suficiente, y por eso falla.
Aquí, tu opción es dynamic_cast. Otra opción (bastante mejor a mi parecer), es utilizar un objeto AB*:
#include <iostream>
using namespace std;
class A{
public:
virtual void opA() = 0;
};
class B{
public:
virtual void opB() = 0;
};
class AB: public A, public B{
public:
void opA(){
cout<<"Operacion A"<<endl;
}
void opB(){
cout<<"Operacion B"<<endl;
}
};
int main(){
AB* ab = new AB();
A* variableA = ab;
B* variableB = ab;
variableA->opA();
variableB->opB();
delete ab;
return 0;
}
No necesitarás hacer casts (el cast implícito funciona correctamente en este caso), y además tendrás la certeza de que los tipos son siempre válidos.
En tu ejemplo, estás convirtiendo un A* a un B*. Viendo el código, sabemos que eso funciona, pero no es
realmente válido, pues esas clases no tienen relación.
Este último método es preferible ante el dynamic_cast porque te dará error en tiempo de compilación (preferible a una excepción), y la transformación es más rápida (dynamic_cast hace comprobaciones que podemos obviar).
Cuidado con reinterpret_cast a la hora de trabajar con clases. Mejor evitarlo, especialmente cuando se utiliza herencia múltiple.
Un caso de uso de reinterpret_cast podría ser:
int n = 456;
char* bytesDeN = reinterpret_cast<char*>(&n);
EDITO: Y sobre el por qué hace lo que dices, pues: reinterpret_cast en ese caso no hará un cast correcto, y el comportamiento será indefinido. Probablemente, como opA es la primera función, B la coja como si fuera opB. En cualquier caso, este comportamiento es indefinido y no es relevante. Simplemente, debe evitarse.