2010-01-17 12 views
12

Ho qualcosa di simile a questo nel mio codice:tavoli virtuali su classi anonime

#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; 
} 

mi aspetto questo per dare questa uscita:

ble: 1 
ble: 2 

E lo fa, quando compilato sotto GCC (3.4.5 credo).

compilazione e l'esecuzione di questo in Visual Studio 2008 tuttavia, dà questo:

ble: 2 
ble: 2 

Ciò che è interessante, è che se io do le struct nomi Base-derivato (struct s1 : public Base), funziona correttamente.

Quale comportamento, se presente, è corretto? VS è semplicemente pazza o aderisce allo standard? Mi sto perdendo qualcosa di vitale qui?

+1

Funziona come previsto in gcc.Anche se per essere sincero, mi aspettavo che non si compilasse. –

+2

* VS aderente allo standard *? Ah ah ah ah ah ... – wallyk

+3

Ehi, VC++ è diventato molto meglio. – GManNickG

risposta

2

È visibile l'errore di MSVC dai simboli di debug. Genera nomi temporanei per le strutture anonime, rispettivamente Child::<unnamed-type-First> e Child::<unnamed-type-Second>. C'è comunque solo un vtable, è chiamato Child::<unnamed-tag>::'vftable' ed entrambi i costruttori lo usano. Il diverso nome per il vtable è sicuramente parte del bug.

Sono stati segnalati numerosi bug su connection.microsoft.com relativi a tipi anonimi, nessuno dei quali è mai stato impostato su "must-fix". Non quello che hai trovato, afaict. Forse la soluzione è troppo semplice.

7

Sembra che questo sia un bug in VS 2008, probabilmente perché sovrascrive o ignora il vtable per la prima classe senza nome in favore del vtable per il secondo poiché i nomi interni sono identici. (Quando ne nominate uno esplicitamente, i nomi interni per i vtables non sono più identici.)

Per quanto posso dire dallo standard, questo dovrebbe funzionare come vi aspettate e gcc ha ragione.

+0

(+1) spiegazione ben scritta. –

1

Posso confermare che si tratta di un bug noto nel compilatore VC (e si reimposta in VC10); le due classi anonime condividono erroneamente un vtable.

Le strutture anonime sono non parte dello standard C++.

Modifica: le strutture anonime sono un termine ambiguo. Può significare due cose:

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

    struct { 
     int c; 
    };  // 2 

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

1 è quello che sta succedendo qui, un nome migliore di struct anonimo sarebbe "struct senza nome". Il tipo struct stesso non ha un nome, ma l'oggetto fa (m_a).

2 è anche noto come struttura anonima e non è C++ legale. Non esiste un nome oggetto e l'idea è che si può accedere al campo "c" direttamente sugli oggetti di tipo esterno. Questo compila solo a causa di un'estensione del compilatore in Visual Studio (fallirà sotto/Za)

3 Unioni anonime, al contrario, sono C++ legali.

Ho confuso i due, perché qui chiamiamo # 1 una "struttura anonima" e fili nel mio cervello incrociati con # 2.

+0

Le classi senza nome sono C++ standard e talvolta sono chiamate "anonime" anziché "senza nome". –

+0

@ Roger, quello che ho detto è corretto. Ho detto strutture anonime **; ** classi non anonime **. Le classi anonime fanno parte dello standard C++. Le strutture anonime sono una cosa C, e non parte di C++ (sebbene siano ampiamente supportate dall'estensione del venditore, incluso VC). –

+0

"Una struttura è una classe definita con la struttura della chiave di classe ..." [9/4] ** Le strutture sono classi. ** –

Problemi correlati