Abatido en una jerarquía de diamantes


¿Por qué static_cast no puede abatirse desde una base virtual ?

struct A {};
struct B : public virtual A {};
struct C : public virtual A {};
struct D : public B, public C {};

int main()
{
  D d;
  A& a = d;
  D* p = static_cast<D*>(&a); //error
}  

G++ 4.5 dice:

 error: cannot convert from base ‘A’ to derived type ‘D’ via virtual base ‘A’

La solución es usar dynamic_cast ? pero por qué. ¿Qué es lo racional ?

Edit editar {
Muy buenas respuestas a continuación. Sin embargo, no answers detalla exactamente cómo los subobjetos y vtables terminan siendo ordenados. El siguiente artículo da algunos buenos ejemplos para gcc:
http://www.phpcompiler.org/articles/virtualinheritance.html#Downcasting

Author: log0, 2011-05-18

2 answers

Porque si el objeto era realmente de tipo E (derivado de D), la ubicación del subobjeto A en relación con el subobjeto D podría ser diferente a si el objeto es realmente D.

En realidad ya sucede si se considera en su lugar la conversión de A a C. Cuando se asigna C, tiene que contener la instancia de A y vive en algún desplazamiento específico. Pero cuando se asigna D, el subobjeto C se refiere a la instancia de A que vino con B, por lo que es desplazamiento es diferente.

 10
Author: Jan Hudec,
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
2011-05-18 12:33:57

La respuesta obvia es: porque la norma lo dice. El la motivación detrás de esto en el estándar es que static_cast debe estar cerca de trivial-a lo sumo, una simple adición o resta de una constante al puntero. ¿Dónde está el abatido? a una base virtual requeriría código más complicado: tal vez incluso con una entrada adicional en el vtable en algún lugar. (Se requiere algo más que constantes, ya que la posición de D en relación con A puede cambiar si hay más derivación.) El conversión es obviamente factible, ya que cuando se llama una función virtual en un A*, y la función se implementa en D, el compilador debe hacerlo, pero la sobrecarga adicional fue considerado inapropiado para static_cast. (Presumiblemente, el la única razón para usar static_cast en tales casos es optimización, ya que dynamic_cast es normalmente el preferido solución. Así que cuando static_cast es probable que sea tan caro como dynamic_cast de todos modos, ¿por qué apoyarlo.)

 11
Author: James Kanze,
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
2011-05-18 12:42:50