9
votes

Comment C ++ Magasinez-vous des fonctions et des objets en mémoire?

permet de dire que nous avons une classe xxx pré>

Le code ci-dessus compilera sur Turbo C (où j'ai testé) et imprimer hi code> comme sortie. P>

Je m'attendais à un crash parce que a code> est null code>. Plus sur si je fais Sayhi () code> fonction virtuelle, il est écrit p>

Abnormal temination(Segmentation fault in gcc) 


2 commentaires

Appeler une méthode via un pointeur NULL est un comportement indéfini. Tout peut arriver - il n'est pas nécessaire de s'écraser, mais la norme le permet.


Pas un gars C ++, donc ceci est une suppose, mais: votre code n'a pas besoin d'accéder à la mémoire d'une instance de A . Sayhi () n'utilise pas le champ x , et ce n'est pas virtuel, il n'est donc pas nécessaire d'accéder à la tablette pour résoudre. Un compilateur C ++ devra réellement insérer un chèque pour voir si A est un pointeur valide pour provoquer une erreur.


4 Réponses :


6
votes

en C ++, les méthodes d'une classe ne sont pas stockées dans les instances de cette classe. Ils sont simplement des fonctions «spéciales» qui acceptent de manière transparente le pointeur en plus des arguments spécifiés par le programmateur.

Dans votre cas, la méthode Sayhi () ne fait référence à aucun des champs de classe, par conséquent, le pointeur (qui est null ) n'est jamais suivi.

Ne faites aucune erreur, cependant, cela reste un comportement non défini. Votre programme peut choisir d'envoyer des e-mails Nasty à votre liste de contacts lorsque vous l'invoquerez. Dans ce cas particulier, il fait la pire chose et semble fonctionner.

Le cas de méthode a été ajouté depuis que j'ai répondu à la question, mais je ne vais pas affiner ma réponse, car elle est incluse par les réponses des autres.


1 commentaires

+1 pour souligner ce comportement non défini qui "fonctionne" est mauvais.



7
votes

Évidemment, le code a un comportement indéfini, c'est-à-dire que ce que vous obtenez, c'est par hasard. Cela dit, le système n'a pas besoin de savoir sur l'objet lors de la convocation d'une fonction de membre non virtuel: elle peut simplement être appelée en fonction de la signature. En outre, si une fonction membre n'a pas besoin d'accéder à un membre, il n'a pas besoin de vraiment besoin d'un objet du tout et peut simplement courir. C'est ce que vous avez observé lorsque le code imprimait une sortie. Qu'il s'agisse de la manière dont le système est mis en œuvre n'est pas défini, cependant, rien ne dit que cela fonctionne.

Lorsque vous appelez un système de type de fonction virtuel, le système commence à regarder un enregistrement d'informations de type associé à l'objet. Lorsque vous appelez une fonction virtuelle sur un pointeur null , aucune information de ce type n'existe et qui tente d'y accéder, conduit probablement à une sorte de crash. Néanmoins, cela n'a pas besoin, mais cela fait pour la plupart des systèmes.

BTW, Main () Toujours Retours int .


0 commentaires

1
votes

Si vous appelez une méthode non virtuelle d'une classe, pour le compilateur, il suffit de savoir quelle classe la fonction appartient à et par la derréférance - bien qu'un pointeur null à une classe pour appeler la méthode, le compilateur obtient cette informations. La méthode Sayhi () est à peu près une fonction qui prend le pointeur à l'instance de classe en tant que paramètre caché. Ce pointeur est null mais cela n'a pas d'importance si vous ne faites pas référence à aucun attribut dans la méthode.

Le moment où vous faites cette méthode virtuelle, la situation change. Le compilateur ne sait pas quel code est associé à la méthode au moment de la compilation et doit comprendre cela au moment de l'exécution. Ce qu'il fait, c'est qu'il regarde une table qui contient essentiellement des pointeurs de fonction pour toutes les méthodes virtuelles; Cette table est associée à l'instance de classe, de sorte qu'il regarde le morceau de la mémoire par rapport au pointeur NULL et se bloque donc dans ce cas.


0 commentaires

4
votes

comme généralisation, la mise en page d'un objet instancié d'une classe sans classes et fonctions virtuelles est la suivante: xxx

v_ptr est un pointeur à La table V - qui contient des adresses de fonctions virtuelles et de données RTTI pour l'objet. Les classes sans fonctions virtuelles n'ont pas de tables V.

dans votre exemple ci-dessus, Classe A n'a pas de méthodes virtuelles et donc pas de table V. Cela signifie que la mise en œuvre de Sayhi () à appeler peut être déterminée à l'heure de la compilation et est invariante.

Le compilateur génère un code qui définit le pointeur implicite Ceci sur A , puis passe au début de Sayhi () . Étant donné que la mise en œuvre n'a pas besoin de contenu de l'objet, le fait qu'il fonctionne lorsque le pointeur est null est une coïncidence heureuse.

Si vous deviez faire Sayhi () Virtual, le compilateur ne peut pas déterminer la mise en œuvre à appeler à l'heure du compilateur. Génère donc le code qui lève l'adresse de la fonction dans le Table V-Table et l'appelle. Dans votre exemple où a est null , le compilateur lit le contenu de l'adresse 0 , provoquant l'avortement.


1 commentaires

Le fait que la classe A n'a pas de méthodes virtuelles n'est pas pertinente. Ce qui est important, c'est que la fonction particulière soit appelée, Sayhi, n'est pas une fonction virtuelle et n'utilise pas les membres de l'objet de classe. Cette fonction peut donc être appelée (et est) appelée sans utiliser le pointeur sur l'objet de la classe.