2010-01-17 36 views
12

que tienen algo similar a esto en mi código:tablas virtuales en clases anónimas

#include <iostream> 
#include <cstdlib> 

struct Base 
{ 
    virtual int Virtual() = 0; 
}; 

struct Child 
{ 
    struct : public Base 
    { 
    virtual int Virtual() { return 1; } 
    } First; 

    struct : public Base 
    { 
    virtual int Virtual() { return 2; } 
    } Second; 
}; 

int main() 
{ 
    Child child; 
    printf("ble: %i\n", ((Base*)&child.First)->Virtual()); 
    printf("ble: %i\n", ((Base*)&child.Second)->Virtual()); 

    system("PAUSE"); 
    return 0; 
} 

yo esperaría que esto da este resultado:

ble: 1 
ble: 2 

y lo hace, cuando se compila bajo GCC (3.4.5 Yo creo).

Compilación y ejecución de este en Visual Studio 2008, sin embargo, da esto:

ble: 2 
ble: 2 

Lo que es interesante, es que si doy los nombres structs Base derivados (struct s1 : public Base), funciona correctamente.

¿Qué comportamiento, en su caso, es correcto? ¿VS simplemente es priestrado o se está apegando al estándar? ¿Me estoy perdiendo algo vital aquí?

+1

Funciona como se espera en gcc.Aunque para ser franco estaba esperando que no compilara. –

+2

* VS se adhiere al estándar *? Ja, ja, ja, ja ... – wallyk

+3

Oye, VC++ ha mejorado mucho en eso. – GManNickG

Respuesta

2

Es visible cómo MSVC lo está equivocando a partir de los símbolos de depuración. Genera nombres temporales para las estructuras anónimas, respectivamente Child::<unnamed-type-First> y Child::<unnamed-type-Second>. Sin embargo, solo hay un vtable, se llama Child::<unnamed-tag>::'vftable' y ambos constructores lo usan. El diferente nombre para el vtable seguramente es parte del error.

Hay varios errores reportados en connection.microsoft.com que están relacionados con tipos anónimos, ninguno de los cuales llegó al estado "debe corregir". No es el que encontraste, afaict. Tal vez la solución sea demasiado simple.

7

Parece que se trata de un error en VS 2008, posiblemente porque sobrescribe o ignora el vtable para la primera clase sin nombre a favor del vtable para el segundo ya que los nombres internos son idénticos. (Cuando nombra uno explícitamente, los nombres internos de los vtables ya no son idénticos).

Por lo que puedo decir del estándar, esto debería funcionar como esperaba y gcc es correcto.

+0

(+1) explicación bien escrita. –

1

Puedo confirmar que este es un error conocido en el compilador de VC (y repositorios en VC10); las dos clases anónimas están compartiendo incorrectamente un vtable.

Las estructuras anónimas son no parte del estándar C++.

Editar: Las estructuras anónimas son un término bastante ambiguo. Puede significar dos cosas:

class outer 
{ 
public: 
    struct { 
     int a; 
     int b; 
    } m_a; // 1 

    struct { 
     int c; 
    };  // 2 

    union { 
     int d; 
     int e; 
    };  // 3 
}; 

1 es lo que está pasando aquí, un nombre mejor que el anonimato estructura sería "estructura sin nombre". El tipo de estructura en sí no tiene un nombre, pero el objeto sí (m_a).

2 también se conoce como una estructura anónima, y ​​no es legal C++. No hay un nombre de objeto, y la idea es que podría acceder al campo 'c' directamente en objetos de tipo externo. Esto solo se compila a causa de una extensión de compilador en Visual Studio (fallará en/Za)

3 Las uniones anónimas, por el contrario, son legales C++.

Confundí los dos, porque aquí estamos llamando al # 1 una "estructura anónima", y los cables en mi cerebro se cruzaron con el # 2.

+0

Las clases sin nombre son estándar C++ y a veces se llaman "anónimo" en lugar de "sin nombre". –

+0

@Roger, lo que dije es correcto. Dije ** anónimo **; no ** clases ** anónimas Las clases anónimas son parte del estándar C++. Las estructuras anónimas son una cosa C, y no una parte de C++ (aunque son ampliamente compatibles con la extensión de proveedor, incluido VC). –

+0

"Una estructura es una clase definida con la estructura de clave de clase ..." [9/4] ** Las estructuras son clases. ** –

Cuestiones relacionadas