84 votes

Héritage: 'A' est une base inaccessible de 'B'

$ cat inheritance.cpp 
#include <iostream>

using namespace std;

class A { };
class B : private A { };

int main() {
    A* ab = new B;
}
$
$ g++ inheritance.cpp
inheritance.cpp: In function 'int main()':
inheritance.cpp:9: error: 'A' is an inaccessible base of 'B'
$

Je ne comprends pas cette erreur.

Ce que je comprends, et comme ce tutoriel confirme, private d'héritage ne devrait changer la façon dont les membres de l' class B sont visibles à l'extérieur.

Je pense que le privé spécificateur de faire plus que juste changer la visibilité de l' class B des membres ici.

  • Que dois-je reçois ce message d'erreur et ça veut dire quoi?
  • Fondamentalement, quel est le problème avec permettre à ce type de code en C++? Semble totalement inoffensif.

103voto

Jerry Coffin Points 237758

En faisant de l'héritage privé, vous êtes essentiellement en disant que même le fait que B hérite de A (à tous) est privé-non accessible et visible de l'extérieur.

Sans entrer dans un long-winded discussion de ce qui se passerait si elle était autorisée, le simple fait est qu'il n'est pas permis. Si vous souhaitez utiliser un pointeur à la base pour faire référence à un objet de type dérivé, alors vous êtes un peu coincé avec l'aide publique héritage.

Edit: Depuis que quelqu'un a pris la peine d'envoyer un mail pour demander plus d'informations à propos de ce qui pourrait arriver si cela était autorisé, je crois que je vais en dire un peu plus sur elle.

Le problème de base est que, privé de l'héritage est pas nécessairement l'intention de suivre le principe de substitution de Liskov. Patrimoine Public affirme qu'un objet dérivé peut être remplacé par un objet de la classe de base, et la bonne sémantique aura toujours raison. Privé de l'héritage n' a pas d'affirmer que, bien que. La description habituelle de la relation implicite privé, l'héritage est "est mis en œuvre en termes de".

Patrimoine Public désigne une classe dérivée de conserve toutes les fonctionnalités de la classe de base et potentiellement ajoute de plus en plus. Privé de l'héritage signifie souvent plus ou moins le contraire: que la classe dérivée utilise un général de la classe de base pour mettre en place quelque chose avec un nombre plus restreint de l'interface.

Juste pour exemple, supposons pour le moment que les conteneurs dans la norme C++ de la bibliothèque ont été mis en œuvre en utilisant l'héritage plutôt que de modèles. Dans le système actuel, std::deque et std::vector sont des conteneurs, et std::stack est un adaptateur de conteneur qui fournit une plus restreint de l'interface. Puisqu'il est basé sur des modèles, vous pouvez utiliser std::stack comme un adaptateur pour std::deque ou std::vector.

Si nous voulions essentiellement la même chose avec l'héritage, nous ne serions probablement l'utilisation privée de l'héritage, alors std::stack serait quelque chose comme:

class stack : private vector {
    // ...
};

Dans ce cas, nous avons certainement ne pas vouloir l'utilisateur d'être en mesure de manipuler nos stack comme si c'était un vector. Cela pourrait (et probablement) ne contreviennent pas à la hauteur des attentes d'une pile (par exemple, l'utilisateur peut insérer/supprimer des éléments dans le milieu, plutôt que purement pile-comme la mode comme prévu). Nous sommes essentiellement à l'aide d' vector comme un moyen pratique de mettre en œuvre notre stack, mais si (par exemple), nous avons changé la mise en œuvre de stack autonome (avec pas de dépendance sur une classe de base) ou de re-mettre en œuvre en termes de std::deque, nous n'avons pas envie que ça affecte tout le code client, le code client, c'est censé être juste une pile, pas spécialisée variété de vecteur (ou deque).

12voto

Ben Voigt Points 151460

l'héritage privé ne devrait changer que la manière dont les membres de la classe B sont visibles au monde extérieur

Cela fait. Et si

 A* p = new B;
 

étaient autorisés, les membres hérités de B pouvaient être accédés du monde extérieur, simplement en faisant un A* . Étant donné qu'ils ont hérité en privé, cet accès est illégal, de même que la diffusion ascendante.

8voto

Carl Norum Points 114072

clang++ donne un peu plus compréhensible le message d'erreur:

example.cpp:9:13: error: cannot cast 'B' to its private base class 'A'
    A* ab = new B;
            ^
example.cpp:6:11: note: declared private here
class B : private A { };
          ^~~~~~~~~
1 error generated.

Je ne suis pas un C++ expert, mais il semble que c'est juste tout simplement pas permis. Je vais aller fouiller dans la spécification et voir ce que je produis.

Edit: voici la référence pertinente de la spec - Section 4.10 Pointeur de conversions, paragraphe 3:

Un prvalue de type "pointeur vers cv D", où l' D est un type de classe, peuvent être convertis en un prvalue de type "pointeur vers cv B", où B est une classe de base de l' D. Si B est inaccessible ou ambiguë de la classe de base de l' D, un programme qui nécessite cette conversion est mal formé.

5voto

Ernest Friedman-Hill Points 56605

C'est assez simple: le fait que A soit hérité en privé signifie que le fait que B prolonge A est un secret, et seulement B "le sait" C'est la définition même de l'héritage privé.

3voto

tmpearce Points 8306

Héritage privé signifie qu'en dehors de la classe dérivée, les informations d'héritage sont masquées. Cela signifie que vous ne pouvez pas convertir la classe dérivée en classe de base: la relation n'est pas connue de l'appelant.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X