Pour la deuxième question, c'est probablement parce que vous ne le faites pas implicitement définir . Si le constructeur est simplement déclaré implicitement, il n'y a pas d'erreur. Exemple:
struct A { A(int); };
struct B : A { };
// goes fine up to here
// not anymore: default constructor now is implicitly defined
// (because it's used)
B b;
Pour votre première question, cela dépend du nom utilisé par le compilateur. Je ne sais pas ce que la norme précise, mais ce code par exemple est correct parce que le nom de la classe externe (au lieu du nom de la classe héritée) est accessible:
class A {};
class B: private virtual A {};
class C: public B { C(): ::A() { } }; // don't use B::A
Peut-être que la norme est underspecified à ce stade. Nous devrons regarder.
Il ne semble pas y avoir de problème avec le code. De plus, il y a une indication que le code est valide. Le sous-objet de classe de base (virtuel) est initialisé par défaut - il n'y a pas de texte qui implique que la recherche de nom pour le nom de la classe est diner dans la portée de C
.Voici ce que dit Standard:
12.6.2/8
(C++ 0x)
Si un membre de données non statique, ou une classe de base ne sont pas nommés par un mem-initialiseur-id (y compris le cas où il n'y a pas mem-initialiseur liste parce que le constructeur n'a pas cteur-initialiseur) et l'entité n'est pas une classe de base virtuelle d'une classe abstraite
[...] sinon, l'entité est par défaut-initialisés
Et C++ 03 a un texte similaire (texte moins clair - il dit simplement que son constructeur par défaut est appelé à un endroit, et à un autre il le rend dépendant si la classe est un POD). Pour que le compilateur initialise le sous-objet par défaut, il doit simplement appeler son constructeur par défaut - il n'est pas nécessaire de chercher le nom de la classe de base en premier (sait déjà quelle base est considérée).
Considérez ce code qui est certainement destiné à être valable, mais cela échouera si ce serait être fait (voir 12.6.2/4
en C++ 0x)
struct A { };
struct B : virtual A { };
struct C : B, A { };
C c;
Si le constructeur par défaut du compilateur simplement regarder -up nom de la classe A
à l'intérieur de C
, il aurait un résultat de recherche ambiguë en ce qui concerne ce sous-objet à initialiser, parce que les A
non-virtuel et les noms de classe A
virtuel sont trouvés. Si votre code est destiné à être mal formé, je dirais que la norme doit certainement être clarifiée.
Pour le constructeur, notez ce que 12.4/6
dit au sujet de la destructor de C
:
Tous les Destructeurs sont appelés comme si elles étaient référencées avec un nom qualifié, qui est, sans tenir compte des Destructeurs prépondérants virtuels possibles dans plus de classes dérivées.
Cela peut être interprété de deux façons:
- appeler A :: ~ A()
- appeler :: A :: ~ A()
Il semble moi que la norme est moins claire ici. La deuxième façon de le rendre valide (par 3.4.3/6
, C++ 0x, parce que les deux noms de classe A
sont recherchés dans la portée globale), tandis que le premier le rendra invalide (parce que les deux A
trouveront les noms de classe hérités). Cela dépend aussi de quel sous-objet la recherche commence (et je crois que nous devrons utiliser le sous-objet de la classe de base virtuelle comme point de départ). Si cela va comme
virtual_base -> A::~A();
Ensuite, nous allons trouver directement la base virtuelle » nom de classe comme un nom public, parce que nous ne passer par la classe dérivée champs d'application et de trouver le nom non accessible. Encore une fois, le raisonnement est similaire.Tenir compte:
struct A { };
struct B : A { };
struct C : B, A {
} c;
Si le destructor serait simplement appeler this->A::~A()
, cet appel ne serait pas valide en raison du résultat de recherche ambiguë de A
comme un nom de classe héritée (vous ne pouvez pas se référer à une non-statique membre fonction du diriger l'objet de classe de base de la portée C
, voir 10.1/3
, C++ 03). Il devra uniquement identifier les noms de classe concernés et doit commencer par la référence de sous-objet de la classe, telle que a_subobject->::A::~A();
.
Avec g ++ 4.4, il compile. Bien que je n'ai pas été en mesure de trouver une référence faisant autorité, je crois qu'il devrait compiler. La classe la plus dérivée 'C' peut construire le sous-objet de type' A'. Notez qu'il existe des implémentations pour sceller l'héritage sur la base de la combinaison de l'héritage 'private virtual '* ensemble * avec un constructeur privé dans' A' et de l'accès accordé '' '' par amitié. Toute la complication serait inutile si juste utiliser l'héritage virtuel privé suffirait. –
@ DavidRodríguez-dribeas "_Toute la complication serait inutile s'il suffisait d'utiliser l'héritage virtuel privé." Personne ici n'a prétendu que l'idiome de cachetage fonctionne sans un cteur privé. Dans l'idiome de cachetage, l'héritage privé n'est pas nécessaire, mais il est nécessaire pour que l'utilisation de l'idiome soit un détail d'implémentation. – curiousguy