Question

considérez le code suivant:

class A
{
    friend class B;
    friend class C;
};

class B: virtual private A
{
};

class C: private B
{
};

int main()
{
    C x; //OK default constructor generated by compiler
    C y = x; //compiler error: copy-constructor unavailable in C
    y = x; //compiler error: assignment operator unavailable in C 
}

Le MSVC9.0 (le compilateur C de Visual Studio 2008) fait générer le constructeur par défaut, mais est incapable de générer des opérateurs de copie et d'affectation pour C, bien que C est un ami de A. Est-ce le comportement attendu ou est-ce un Microsoft punaise? Je pense que ce dernier est le cas, et si je ne me trompe pas, quelqu'un peut-il le point à un article / forum / ... où cette question est traitée ou si Microsoft a réagi à ce bogue. Nous vous remercions à l'avance.

P.S. Par ailleurs, si les deux successions privées sont changés pour protéger, tout fonctionne

P.P.S. Il me faut une preuve, que le code ci-dessus est légal ou illégal. Il était en effet prévu qu'une classe avec une base privée virtuelle n'a pas pu être dérivé de ce que je comprends. Mais ils semblent avoir manqué la partie ami. Alors ... ici il va, ma première prime:)

Était-ce utile?

La solution

Votre code compile bien avec Comeau en ligne, et aussi avec MinGW g ++ 4.4.1.

Je mentionner que juste un "argument d'autorité".

D'un accès aux normes POV est orthogonale à l'héritage virtuel. Le seul problème avec l'héritage virtuel est que c'est la plus classe dérivée qui initialise la classe de pratiquement dérivée en amont de la chaîne d'héritage (ou « comme si »). Dans votre cas, la classe la plus dérivée a l'accès requis pour le faire, et donc le code doit compiler.

MSVC a aussi quelques autres problèmes avec l'héritage virtuel.

Alors, oui,

  • le code est valide et
  • il est un bug du compilateur MSVC.

Pour votre information, ce bug est toujours présent dans MSVC 10.0. J'ai trouvé un rapport de bogue au sujet d'un bug similaire, confirmée par Microsoft. Cependant, avec juste un peu rapide googler je ne pouvais pas trouver ce bug particulier.

Autres conseils

La façon dont j'interprète la norme, le code échantillon est bien formé. (Et oui, les déclarations de friend font une grande différence par rapport à la chose Townsend cité @ Steve.)

  

11.2p1. Si une classe est déclarée être une classe de base pour une autre classe en utilisant le spécificateur d'accès private, les membres de public et protected de la classe de base sont accessibles en tant que membres de private de la classe dérivée

     

11.2p4: Un membre m est accessible lorsque nommé en classe N si

  • m en tant que membre de N est publique, ou
  • m en tant que membre de N est privé, et la référence se produit dans un membre ou un ami de classe N , ou
  • m en tant que membre de N est protégée, et la référence se produit dans un organe ou un ami de la classe N , ou dans un élément ou un ami d'une classe P dérivé de N , où m en tant que membre de P est privé ou protégé, ou
  • il existe une classe de base B de N qui est accessible au point de référence, et m est accessible lorsque le nom en classe < em> B .
  

11.4p1. Un ami d'une classe est une fonction ou une classe qui ne fait pas partie de la catégorie, mais est autorisée à utiliser les noms de membres privés et protégés de la classe

Il n'y a pas de déclarations à l'article 11 (contrôle d'accès) membres qui impliquent qu'un ami d'une des autorisations d'accès de classe a de moins en moins que la classe qui se lie d'amitié elle. Notez que n'est définie « accessible » dans le contexte d'une classe spécifique. Bien que l'on parle parfois d'un membre ou d'une classe de base étant « accessibles » ou « inaccessible » en général, il serait plus exact de parler si elle est « accessible dans tous les contextes » ou « accessible dans toutes les classes » (comme cela est le cas lorsque l'on utilise seulement public).

Maintenant, pour les parties qui décrivent des contrôles sur le contrôle d'accès dans les méthodes définies automatiquement.

  

12.1p7: Un constructeur par défaut implicite déclarée pour une classe est défini implicitement quand il est utilisé pour créer un objet de ce type de classe (1,8). Le constructeur par défaut implicitement définis exécute l'ensemble de initialisations de la classe qui seraient effectuées par un constructeur par défaut écrit par l'utilisateur pour cette classe avec un vide mem-initialiseur-list (12.6.2) et un corps de la fonction vide. Si ce constructeur par défaut écrit par l'utilisateur serait mal formé, le programme est mal formé.

     

12.6.2p6: Tous les sous-objets représentant les classes de base virtuelles sont initialisés par le constructeur de la classe la plus dérivée (1,8). Si le constructeur de la classe la plus dérivée ne spécifie pas de mem-initialiseur pour une V de classe de base virtuelle, puis le constructeur par défaut de V est appelé pour initialiser le sous-objet de classe de base virtuelle. Si V ne dispose pas d'un constructeur par défaut accessible, l'initialisation est mal formé.

     

12.4p5: Une destructor implicitement déclarée est défini implicitement quand il est utilisé pour détruire un objet de ce type de classe (3,7). Un programme est mal formé si la classe pour laquelle est définie implicitement un destructor a:

  • un élément de données non-statique de type de classe (ou d'une matrice de celui-ci) avec un destructeur inaccessible, ou
  • une classe de base avec un destructor inaccessible.
  

12.8p7: un constructeur de copie implicitement déclarée est défini implicitement si elle est utilisée pour initialiser un objet de ce type de classe à partir d'une copie d'un objet de ce type de classe ou d'un type de classe dérivée de son type de classe. [Note: le constructeur de copie est implicitement défini, même si la mise en œuvre élide son utilisation (12.2).] Programme A est mal formé si la classe pour laquelle un constructeur de copie est implicitement défini has:

  • un élément de données non statique de type de classe (ou l'ensemble) avec un constructeur de copie inaccessible ou ambiguë, ou
  • une classe de base avec un constructeur de copie inaccessible ou ambiguë.
  

12.8p12: programme A est mal formé si la classe pour laquelle est définie implicitement un opérateur d'affectation de copie a:

  • un élément de données non statique de type const, ou
  • un élément de données non statique du type de référence, ou
  • un élément de données non statique de type de classe (ou l'ensemble) avec un opérateur d'affectation de copie inaccessible, ou
  • une classe de base avec un opérateur d'affectation de copie inaccessible.

Toutes ces exigences avec la mention « inaccessible » ou « accessible » doit être interprété dans le contexte d'une classe, et la seule classe qui fait sens est celui pour lequel une fonction de membre est implicitement défini.

Dans l'exemple original, class A a implicitement public constructeur par défaut, destructor, constructeur de copie et de copie opérateur d'affectation. Par 11.2p4, puisque class C est un ami de class A, tous les membres sont accessibles lorsque le nom de la classe C. Par conséquent, les contrôles d'accès aux membres du class A ne causent pas les définitions implicites du constructeur par défaut de class C, destructor, constructeur de copie ou de copie opérateur d'affectation à mal formé.

Les classes avec base de virtual private ne doit pas être dérivé, par cette au C ++ SWG. Le compilateur fait la bonne chose (jusqu'à un certain point). La question n'est pas la visibilité de A de C, il est que C ne doit pas être autorisé à être instancié du tout, ce qui implique que le bogue est dans le premier (par défaut) la construction plutôt que les autres lignes.

  
      
  1. Peut une classe avec un être dérivé de? Classe de base virtuelle privée
  2.   
     

Section: 11.2 [class.access.base]
  Statut: NAD Déposant: Jason   Merrill Date: inconnu

class Foo { public: Foo() {}  ~Foo() {} };
class A : virtual private Foo { public: A() {}  ~A() {} };
class Bar : public A { public: Bar() {}  ~Bar() {} }; 
  

~ appels Bar ()   ~ Foo (), qui est mal formé en raison de   violation d'accès, non? (Bar est   constructeur a le même problème depuis   il a besoin d'appeler le constructeur de Foo.)   Il semble y avoir un certain désaccord   parmi les compilateurs. Sun, IBM et g ++   rejeter la testcase, EDG et HP acceptent   il. Peut-être que ce cas devrait être   clarifié par une note dans le projet. Dans   Bref, il ressemble à une classe avec un   base privée virtuelle ne peut pas être dérivé   de.

     

Justification:. Voici ce qui était prévu

btw le comportement du compilateur Visual C v10 de est le même comme il est indiqué dans la question. Suppression virtual de l'héritage de A dans B résout le problème.

Je pense que ce n'est pas un bug. Juste C doit être un ami de B pour être en mesure de le copier de la classe de base virtuelle A.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top