Todos sabemos que cuando se usa una herencia simple simple, la dirección de una clase derivada es la misma que la dirección de la clase base. La herencia múltiple hace que eso sea falso.
¿La herencia virtual también hace que eso sea falso? En otras palabras, ¿es correcto el siguiente código?
struct A {};
struct B : virtual A
{
int i;
};
int main()
{
A* a = new B; // implicit upcast
B* b = reinterpret_cast<B*>(a); // fishy?
b->i = 0;
return 0;
}
c++
virtual-inheritance
usuario1610015
fuente
fuente

reinterpret_castwith classes es siempre sospechoso (excepto de clase avoid*, y de regreso a la misma clase).Respuestas:
Creo que la afirmación no es cierta. En el siguiente código, tenemos una herencia simple (no virtual) simple (no múltiple), pero las direcciones son diferentes.
y la salida para VS2015 es:
Si cambia la herencia en el código anterior a virtual, el resultado será el mismo. así, incluso en el caso de la herencia virtual, las direcciones de los objetos base y derivados pueden ser diferentes.
fuente
void main()es aceptable incluso en los compiladores modernos de MSVS. Por cierto, gracias por el comentario. He actualizado el código.void main()no es aceptable Tiene que estar deint main()acuerdo con el estándar. Y elimine esodynamic_castdel código, no es necesario allí y causa confusión.El resultado de
reinterpret_cast<B*>(a);solamente está garantizada a punto a la envolventeBobjeto deasi elasubobjeto y la envolventeBobjeto son puntero-interconvertibles , ver [expr.static.cast] / 3 de la C ++ 17 estándar.El objeto de clase derivado es interconvertible con el puntero con el objeto de clase base solo si el objeto derivado es un diseño estándar , no tiene miembros de datos directos no estáticos y el objeto de clase base es su primer subobjeto de clase base. [basic.compound] /4.3
Tener una
virtualclase base descalifica a una clase de ser un diseño estándar . [clase] /7.2 .Por lo tanto, debido a que
Btiene una clase base virtual y un miembro de datos no estático,bno apuntará alBobjeto que lo encierra , sino quebel valor del puntero permanecerá sin cambios con respectoaal de.Acceder al
imiembro como si estuviera apuntando alBobjeto tiene un comportamiento indefinido.Cualquier otra garantía provendría de su ABI específico u otra especificación.
fuente
Eso no es del todo correcto. Considere este ejemplo:
Al crear una instancia de
D,ByCse instancian cada uno con su instancia respectiva deA. Sin embargo, no habría ningún problema si la instancia deDtuviera la misma dirección de su instancia deBy su respectiva instancia deA. Aunque no es obligatorio, esto es exactamente lo que sucede al compilarclang 11ygcc 10:Consideremos una versión modificada del ejemplo anterior:
El uso del
virtualespecificador de funciones se usa generalmente para evitar llamadas ambiguas a funciones. Por lo tanto, cuando se usa lavirtualherencia, ambosBy lasCinstancias deben crear unaAinstancia común . Al crear instanciasD, obtenemos las siguientes direcciones:Aquí no hay ninguna razón para usar
reinterpret_cast, aún más, resulta en un comportamiento indefinido. Use en sustatic_castlugar:Ambos lanzamientos se comportan de manera diferente en este ejemplo. La
reinterpret_castreinterpretarápBcomo un puntero aA, pero el punteropApuede apuntar a una dirección diferente, como en el ejemplo anterior (C vs A). El puntero se subirá correctamente si lo usastatic_cast.fuente
La razón
aybson diferentes en su caso es porque, dadoAque no tiene ningún método virtual,Ano está manteniendo avtable. Por otro lado,Bmantiene avtable.Cuando se sube a
A, el compilador es lo suficientemente inteligente como para omitir lovtableprevistoB. Y de ahí la diferencia en las direcciones. No deberíasreinterpret_castvolver aBhacerlo, no funcionaría.Para verificar mi reclamo, intente agregar un
virtualmétodo, digamosvirtual void foo() {}enclass A. AhoraAtambién mantendrá avtable. Por lo tanto, downcast (reinterpret_cast) a B le devolverá el originalb.fuente
Subclass address equal to virtual base class address?tiene que ver con la herencia virtual. Y la herencia virtual tiene que ver con vtables.Agarantice que las direcciones coincidan y que el elenco funcione, ya sea en teoría o en la práctica. No puedo eliminar mi voto negativo sin una edición de publicación, porque se ha bloqueado.