web-dev-qa-db-fra.com

Structure d'un objet C ++ en mémoire contre une structure

Si j'ai une classe comme suit

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

Et une structure comme suit

struct
{
   int x;
   int y;
} example_struct;

Est la structure en mémoire du example_struct similaire à celui de Example_Class

par exemple, si je fais ce qui suit

struct example_struct foo_struct;
Example_Class foo_class = Example_Class();

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

volonté foo_struct.x = 8 et foo_struct.y = 9 (ie: les mêmes valeurs que les valeurs x, y dans la classe foo)?

La raison pour laquelle je demande, c'est que j'ai une bibliothèque C++ (je ne veux pas la changer) qui partage un objet avec du code C et je veux utiliser une structure pour représenter l'objet provenant de la bibliothèque C++. Je ne m'intéresse qu'aux attributs de l'objet.

Je sais que la situation idéale serait d'avoir un enveloppement Example_class autour d'une structure commune entre le code C et C++ mais il ne sera pas facile de changer la bibliothèque C++ en cours d'utilisation.

45
hhafez

La norme C++ garantit que les dispositions de mémoire d'un C struct et d'un C++ class (ou struct - même chose) seront identiques , à condition que le C++ class/struct réponde aux critères d'être [~ # ~] pod [~ # ~] ("Plain Old Data"). Alors, que signifie POD?

Une classe ou une structure est POD si:

  • Tous les membres de données sont publics et eux-mêmes POD ou des types fondamentaux (mais pas des types référence ou pointeur vers membre), ou des tableaux de tels
  • Il n'a pas de constructeurs, d'opérateurs d'affectation ou de destructeurs définis par l'utilisateur
  • Il n'a pas de fonctions virtuelles
  • Il n'a pas de classes de base

Les seuls "isms C++" autorisés sont les fonctions membres non virtuelles, les membres statiques et les fonctions membres.

Étant donné que votre classe a à la fois un constructeur et un destructeur, elle n'est formellement pas de type POD, donc la garantie ne tient pas. (Bien que, comme d'autres l'ont mentionné, dans la pratique, les deux dispositions sont susceptibles d'être identiques sur tous les compilateurs que vous essayez, tant qu'il n'y a pas de fonctions virtuelles).

Voir la section [26.7] du C++ FAQ Lite pour plus de détails.

62
j_random_hacker

La structure en mémoire de l'exemple_struct est-elle similaire à celle de Example_Class

Le comportement n'est pas garanti et dépend du compilateur.

Cela dit, la réponse est "oui, sur ma machine", à condition que la classe Example_Class ne contienne aucune méthode virtuelle (et n'hérite pas d'une classe de base).

10
ChrisW

Dans le cas que vous décrivez, la réponse est "probablement oui". Cependant, si la classe possède des fonctions virtuelles (y compris un destructeur virtuel, qui pourrait être hérité d'une classe de base), ou utilise l'héritage multiple, la disposition de la classe peut être différente.

7
Greg Hewgill

Pour ajouter à ce que d'autres personnes ont dit (par exemple: spécifique au compilateur, fonctionnera probablement tant que vous n'avez pas de fonctions virtuelles):

Je suggérerais fortement une assertion statique (vérification au moment de la compilation) que la taille de (Exemple_classe) == sizeof (exemple_struct) si vous faites cela. Voir BOOST_STATIC_ASSERT ou la construction équivalente spécifique au compilateur ou personnalisée. C'est une bonne première ligne de défense si quelqu'un (ou quelque chose, comme un changement de compilateur) modifie la classe pour invalider la correspondance. Si vous souhaitez une vérification supplémentaire, vous pouvez également vérifier à l'exécution que les décalages vers les membres sont les mêmes, ce qui (avec l'assertion de la taille statique) garantira l'exactitude.

3
Nick

Dans les premiers jours des compilateurs C++, il y avait des exemples où le compilateur modifiait d'abord les mots-clés de structure avec la classe, puis compilait. Tellement sur les similitudes.

Les différences proviennent de l'héritage de classe et, en particulier, des fonctions virtuelles. Si la classe contient des fonctions virtuelles, elle doit avoir un pointeur pour taper le descripteur au début de sa mise en page. De plus, si la classe B hérite de la classe A, la disposition de la classe A vient en premier, suivie de la propre disposition de la classe B.

Ainsi, la réponse précise à votre question sur la conversion d'une instance de classe en une instance de structure est la suivante: dépend du contenu de la classe. Pour une classe particulière qui a des méthodes (constructeur et destructeur non virtuel), la disposition va probablement être la même. Si le destructeur était déclaré virtuel, la disposition deviendrait certainement différente entre la structure et la classe.

Voici un article qui montre qu'il n'y a pas grand-chose à faire pour passer des structures C aux classes C++: Leçon 1 - De la structure à la classe

Et voici l'article qui explique comment la table des fonctions virtuelles est introduite dans les classes qui ont des fonctions virtuelles: Leçon 4 - Polymorphisme

1
Zoran Horvat

Les classes et les structures en C++ sont équivalentes, sauf que tous les membres d'une structure sont publics par défaut (les membres de la classe sont privés par défaut). Cela garantit que la compilation du code C hérité dans un compilateur C++ fonctionnera comme prévu.

Rien ne vous empêche d'utiliser toutes les fonctionnalités C++ sophistiquées dans une structure:

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

    /// etc etc etc
};
0
Mike Thompson

Pourquoi ne pas affecter explicitement les membres de la classe aux structures lorsque vous souhaitez passer les données à C? De cette façon, vous savez que votre code fonctionnera n'importe où.

0
Chuck