2010-06-13 6 views
5

Pouvez-vous expliquer pourquoi ce n'est pas autorisé,C++ héritage: la portée et la visibilité des membres

#include <stdio.h> 

class B { 
private: 
    int a; 
public: 
    int a; 
}; 

int main() { 
    return 0; 
} 

alors que c'est?

#include <stdio.h> 

class A { 
public: 
    int a; 
}; 

class B : public A{ 
private: 
    int a; 
}; 

int main() { 
    return 0; 
} 

Dans les deux cas, nous avons un public et une variable privée nommée a dans class B.


édité maintenant!

+0

@Neil: Vous voulez dire que le 2ème déclare une classe A? – Alan

+1

@Alan Oui - J'étais tellement perplexe devant la question que je me suis un peu perdue :-) –

+3

Pourquoi cela a-t-il un downvote? C'est une question raisonnable, je me souviens de me demander la même chose tout en apprenant des cours en C++ ... – Cam

Répondre

15

Dans les deux cas, nous avons un publique et une variable privée nommé dans classe B.

Non, thats pas vrai. Dans le premier cas, vous ne pouvez pas avoir deux identificateurs portant le même nom dans la même portée. Dans le premier cas, vous ne pouvez pas avoir deux identifiants ayant le même nom dans la même étendue. Alors que dans le second cas, B::a cache A::a, et d'accéder A::a vous devez saisir le nom complet:

b.a = 10; // Error. You can't access a private member. 
b.A::a = 10; // OK. 
0

La première n'est pas autorisée car elle conduit à des définitions ambiguës. Dans la 2ème, bien que vous ayez à la fois une variable entière publique et une variable entière a, vous avez caché A :: a dans votre classe B. Le compilateur sait implicitement ce que vous voulez car il existe un moyen d'accéder explicitement à une variable cachée. Je pense aussi que cela se résume à nommer mangaling: les spécificateurs de stockage ne font pas partie du nom réel. Je pourrais avoir tort sur ce point cependant. La façon la plus simple d'illustrer pourquoi un est autorisé et pourquoi l'autre ne l'est pas est de regarder comment le compilateur compilerait une fonction membre qui utilise chaque variable.

l'intérieur de votre classe b:

class b { 

int a; 
public: 
int a; 

void myMethod() 
{ 
a = 10; //what a should the compiler use? Ambiguous, so the compiler sez BZZT. 
} 

} 

Pour le 2ème exemple:

class A 
{ 
public: 
int a; 
} 

class B: public A 
{ 
private: 
int a; 

void someMethod() 
{ 
a = 10; //implied that you are using B::a (which may be a programmer error) 

} 

} 
+0

désolé pour cela. édité maintenant! – Moeb

3

Parce que B::acacheA::a dans le second exemple. Vous pouvez toujours y accéder, mais il faut une qualification explicite pour le compilateur pour comprendre que vous demandez le membre de la classe parent avec le même hame.

Dans le premier exemple, les deux a sont dans la même portée, tandis que dans le second exemple, les étendues sont différentes.

0

classe B dans le premier exemple est pas valide car C++ ne peut pas distinguer les membres de leurs spécificateurs d'accès (public/privé/protégé). Cependant, les espaces de noms sont un moyen pour C++ de distinguer les membres. Dans la classe B du second code, vous n'avez pas de "public a" et de "private a", vous avez B::a et A::a.

Même si déclarer des membres du même nom/signature avec différents spécificateurs d'accès était autorisé, il n'y aurait aucun moyen d'adresser le bon membre.