2017-09-15 8 views
-1

J'essaie d'accéder aux membres privés à l'aide de pointeurs. Je veux savoir pourquoi nous mentionnons dtype devant (int *) & t?Pourquoi faut-il mentionner le type de données devant l'adresse de l'objet pour accéder aux membres privés d'une classe en C++?

class Test 
{ 
private: 
    int data; 
public: 
    Test() { data = 0; } 
    int getData() { return data; } 
}; 

int main() 
{ 
    Test t; 
    int* ptr = (int*)&t; 
    *ptr = 10; 
    cout << t.getData(); 
    return 0; 
} 
+0

cela n'a aucun sens: *** int * ptr = (int *) & t; *** –

+0

Rendre 'data' public si vous avez besoin d'accéder à la valeur directement. Vous pouvez créer des méthodes pour votre classe qui accèdent et manipulent 'data'. Vous devriez éviter de manipuler directement les membres d'une classe en dehors de sa propre portée. –

Répondre

0

(int*)&t: pointeur jette comme un pointeur vers entier

int* ptr = (int*)&t;: il stocke le pointeur de t dans ptr

3

Le système de contrôle d'accès s'applique aux noms. C'est le nom data qui est privé, aucune variable ou zone de stockage associée. En d'autres termes, vous pouvez accéder à la variable d'une autre manière si vous n'utilisez pas le nom data pour le faire.

Le but du contrôle d'accès est d'empêcher le code de se rompre accidentellement encapsulation. On dit parfois que C++ "vous donne assez de corde pour vous pendre", ou "protège contre Murphy mais pas Macchiavelli" - en d'autres termes, vous pouvez contourner le contrôle d'accès si vous le voulez vraiment. Link to related article - GotW #76

Bien sûr, vous devriez essayer de concevoir votre code de manière à ne pas avoir à contourner le contrôle d'accès.


Dans ce cas particulier, le code est bien défini. Comme Test est un standard layout class, il est garanti qu'il n'y a pas de remplissage avant le premier membre de données, et also guaranteed que cette distribution produit un pointeur vers t.data qui peut être utilisé pour accéder à cette variable.

Pour les classes plus compliquées, votre code peut ne pas fonctionner si le membre de données en question ne démarre pas au début de l'espace de stockage de l'objet.

0

Cela ne fonctionne que par hasard pour commencer.

Test est une classe primitive sans héritage impliqué, aucune méthode virtuelle, compilée sans support RTTI, ou toute autre chose qui pourrait gonfler la représentation en mémoire.

Dans cet exemple trivial, la seule variable membre est à la même adresse que l'objet entier. C'est extrêmement dangereux sur lequel s'appuyer, car c'est un comportement indéfini pour quelque chose de plus complexe.

Essayez par ex. maintenant apportant l'héritage et les méthodes virtuelles dans votre test. Soudain, les premiers octets de votre objet ne sont plus la première variable membre (c'est là que le compilateur placera généralement le VPTR), et vous testez les plantages horriblement. Ou faites de votre variable membre une statique à la place, maintenant votre objet lui-même est vide et vous accédez à des structures de contrôle de tas, ce qui ne provoque pas forcément un crash immédiat, mais des corruptions qui sont bien pires. Eh bien, dans ce cas t a été affecté à la pile, donc vous corrompez seulement votre pile à la place (ce qui est légèrement moins pire), mais si le tas était alloué, cela deviendrait critique.