2015-04-06 1 views
1
#include<iostream> 
using namespace std; 

class A 
{ 
    int value; 
public: 
    A(){value = 1;} 
    ~A(){} 

    void print(){cout << value << endl;} 
}; 

int main() 
{ 
    A a; 
    int* p = (int*)(&a); 
    *p = 20; 
    a.print();//output is 20. 
} 

Cela ne rompt-il pas l'encapsulation d'une classe? Je suis un débutant de C++. Je n'ai jamais vu cette méthode qui peut accéder au membre privé d'une classe dans le livre "C++ primer".Pourquoi C++ autorise-t-il l'accès au membre privé d'une classe via un pointeur?

+0

Relatif: http://stackoverflow.com/q/424104/3093378 – vsoftco

Répondre

2

Ceci est autorisé car A est une classe standard_layout, qui est une classe compatible avec la disposition d'autres langages, ce qui signifie qu'elle peut être transmise à des fonctions qui ont été écrites dans autre chose que C++. Il casse l'encapsulation mais ce n'est pas quelque chose que vous voulez faire en C++, c'est une fonctionnalité de compatibilité.

Puisque vous êtes débutant, vous voudrez certainement éviter de faire quoi que ce soit qui implique l'utilisation de lancers de style c/reinterpret_cast. Faites confiance au système de types et aux contrôles d'accès, ils sont là pour vous aider - si vous les remplacez, vous aurez besoin de savoir exactement pourquoi, ce qui n'était évidemment pas le cas ici.

+1

Merci pour la clarification à ma mauvaise réponse maintenant supprimé, j'ai certainement appris quelque chose aujourd'hui. Cependant, avec 'virtual', tous les paris sont désactivés. – vsoftco

1

Votre code est essentiellement un comportement indéfini. Par les lignes suivantes:

int* p = (int*)(&a); 
*p = 20; 

vous déréférencement d'un pointeur punned type, en dépit du fait que ce type calembour ne respecte pas les règles strictes d'aliasing. Pour une version correcte de votre code, A doit être un type agrégé, voir Type aliasing section here. Dans votre code, A n'est pratiquement pas un type agrégat, car il contient un membre privé. Voir la définition d'un agrégat de type here.

+0

Alternativement, 'a.value' et' * p' sont tous deux du même type ('int'), donc les règles strictes d'alias sont respectées. –

+0

Concernant le 4ème point, «A» doit être un type agrégé. Mais ce n'est pas. Le fait que 'a.value' et' * p' soient du même type 'int' ne change rien. Voir le 5ème commentaire à la réponse acceptée dans http://stackoverflow.com/questions/29298508/strict-aliasing-rule-in-c11/. – Lingxi

+0

Désolé pour les commentaires déroutants plus tôt. La règle d'alias strict ne s'applique pas ici. À partir de [class.mem]/20, nous apprenons que «si un objet de classe de mise en page standard possède des membres de données non statiques, son adresse est la même que celle de son premier membre de données non statiques», c'est-à-dire que le compilateur supposer que l'adresse peut se référer à un int aussi bien qu'à un A. – user657267