Domanda

Se ho una lezione come segue

   class Example_Class 
   {
       private:
         int x; 
         int y; 
       public: 
         Example_Class() 
         { 
             x = 8;
             y = 9;
         }
       ~Example_Class() 
       { } 
   };

E una struttura come segue

struct
{
   int x;
   int y;
} example_struct;

La struttura in memoria del esempio_strutto è simile a quella in Example_Class

ad esempio se faccio quanto segue

struct example_struct foo_struct;
Example_Class foo_class = Example_Class();

memcpy(&foo_struct, &foo_class, sizeof(foo_struct));

foo_struct.x = 8 e foo_struct.y = 9 (cioè: gli stessi valori di x, y nella classe foo)?

Il motivo per cui lo chiedo è che ho una libreria C ++ (non voglio cambiarlo) che condivide un oggetto con codice C e voglio usare una struttura per rappresentare l'oggetto proveniente dalla libreria C ++. Sono interessato solo agli attributi dell'oggetto.

So che la situazione ideale sarebbe quella di disporre di Esempio_classe attorno a una struttura comune tra il codice C e C ++, ma non sarà facile cambiare la libreria C ++ in uso.

È stato utile?

Soluzione

Lo standard C ++ garantisce che i layout di memoria di una C struct e una C ++ class (o struct - - stessa cosa) sarà identico, a condizione che la classe C ++ / struct soddisfi i criteri per essere POD (" Plain Old Data ") . Quindi cosa significa POD?

Una classe o struttura è POD se:

  • Tutti i membri dei dati sono POD pubblici e stessi o tipi fondamentali (ma non tipi di riferimento o puntatore a membro) o array di tali
  • Non ha costruttori definiti dall'utente, operatori di assegnazione o distruttori
  • Non ha funzioni virtuali
  • Non ha classi base

Informazioni sull'unico " C ++ - ismi " sono consentite funzioni membro non virtuali, membri statici e funzioni membro.

Poiché la tua classe ha sia un costruttore che un distruttore, non sta parlando formalmente di tipo POD, quindi la garanzia non è valida. (Sebbene, come altri hanno già detto, in pratica i due layout sono probabilmente identici su qualsiasi compilatore che si tenta, a condizione che non ci siano funzioni virtuali).

Vedi la sezione [26.7] del Domande frequenti C ++ Lite per maggiori dettagli.

Altri suggerimenti

  

La struttura in memoria del example_struct è simile a quella in Example_Class

Il comportamento non è garantito ed è dipendente dal compilatore.

Detto questo, la risposta è "sì, sulla mia macchina", a condizione che la Sample_Class non contenga alcun metodo virtuale (e non erediti da una classe base).

Nel caso che descrivi, la risposta è "probabilmente sì". Tuttavia, se la classe ha funzioni virtuali (incluso il distruttore virtuale, che potrebbe essere ereditato da una classe di base) o utilizza l'ereditarietà multipla, il layout della classe potrebbe essere diverso.

Per aggiungere ciò che altre persone hanno detto (ad esempio: specifico del compilatore, probabilmente funzionerà finché non si hanno funzioni virtuali):

Consiglio vivamente un'asserzione statica (controllo del tempo di compilazione) che la dimensione di (Esempio_classe) == dimensione di (esempio_struttura) se lo stai facendo. Vedi BOOST_STATIC_ASSERT o la costruzione equivalente o specifica del compilatore equivalente. Questa è una buona prima linea di difesa se qualcuno (o qualcosa, come una modifica del compilatore) modifica la classe per invalidare la corrispondenza. Se desideri un controllo extra, puoi anche verificare che gli offset ai membri siano gli stessi, che (insieme all'asserzione statica delle dimensioni) garantirà la correttezza.

All'inizio dei compilatori C ++ c'erano esempi in cui il compilatore cambiava prima le parole chiave con la classe e poi le compilava. Tanto sulle somiglianze.

Le differenze derivano dall'ereditarietà delle classi e, soprattutto, dalle funzioni virtuali. Se la classe contiene funzioni virtuali, deve avere un puntatore per digitare il descrittore all'inizio del suo layout. Inoltre, se la classe B eredita dalla classe A, il layout della classe A viene prima, seguito dal layout della classe B.

Quindi la risposta precisa alla tua domanda sul solo lancio di un'istanza di classe in un'istanza di struttura è: dipende dal contenuto della classe. Per una classe particolare che ha metodi (costruttore e distruttore non virtuale), il layout sarà probabilmente lo stesso. Se il distruttore fosse dichiarato virtuale, il layout sarebbe sicuramente diverso tra struttura e classe.

Ecco un articolo che mostra che non c'è molto da fare per passare dalle strutture C alle classi C ++: Lezione 1 - Dalla struttura alla classe

Ed ecco l'articolo che spiega come viene introdotta la tabella delle funzioni virtuali per le classi che hanno funzioni virtuali: Lezione 4 - Polimorfismo

Classi e amp; le strutture in C ++ sono equivalenti, tranne per il fatto che tutti i membri di una struttura sono pubblici per impostazione predefinita (i membri della classe sono privati ??per impostazione predefinita). Ciò garantisce che la compilazione del codice C legacy in un compilatore C ++ funzioni come previsto.

Non c'è nulla che ti impedisca di utilizzare tutte le fantasiose funzionalità C ++ in una struttura:

struct ReallyAClass
{
    ReallyAClass();
    virtual !ReallAClass();

    /// etc etc etc
};

Perché non assegnare esplicitamente i membri della classe alle strutture quando si desidera passare i dati a C? In questo modo sai che il tuo codice funzionerà ovunque.

Probabilmente hai appena derivato la classe dalla struttura, sia pubblicamente che privatamente. Quindi il cast si risolverà correttamente nel codice C ++.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top