2017-10-09 3 views
3

Tenir compte d'un syndicat dont les membres partagent une classe de base commune:Est-il autorisé à accéder à une classe de base commune des membres du syndicat, quel que soit le type stocké?

struct Base { 
    int common; 
}; 

struct DerivedA : Base {}; 
struct DerivedB : Base {}; 

union Union { 
    DerivedA a; 
    DerivedB b; 
}; 

Peu importe ce que l'union « contient » lors de l'exécution (c.-à-ce que la dernière valeur stockée était), tant qu'il contient quelque chose, que quelque chose est la sous-classe Base. Existe-t-il alors un moyen d'utiliser légalement cette idée pour accéder au champ Base, sans connaître le type réel de l'objet stocké dans l'union?

Peut-être quelque chose comme:

Base* p = reinterpret_cast<Base*>(&u); 

... probablement pas. Peut-être ceci:

Base* p2 = static_cast<Base *>(&u.a); 

Est-il légal si u.b était la dernière valeur stockée?

Je sais qu'il existe des règles spéciales sur les "séquences initiales communes" qui s'appliquent aux unions, mais il n'est pas clair s'il existe quelque chose de similaire pour les classes de base. De toute évidence, cela ne fonctionnera pas pour l'héritage multiple, donc c'est peut-être une indication que cela ne fonctionnera pas du tout.

+0

"Une classe de mise en page standard est une classe qui ... a le même contrôle d'accès (article 11) pour tous les membres de données non statiques ... soit n'a aucun membre de données non statiques dans la classe la plus dérivée et la plupart d'une classe de base avec des membres de données non statiques, ou n'a pas de classes de base avec des membres de données non statiques ... "Comme indiqué dans la question,' DerivedA' et 'DerivedB' sont compatibles avec la disposition. Mais dès que les classes dérivées ont un membre de données non statique, elles ne sont plus compatibles avec la mise en page. Mais les classes de base sont, donc ... pas sûrs. –

Répondre

4

Votre exemple exactement comme vous l'avez tapé est en fait valide, mais il ne permet pas de nombreux changements utiles. La seule conversion valide lvalue-à-valeur sur une partie d'un membre inactif d'une union consiste à accéder à une partie de la séquence initiale commune de ce membre avec le membre actif ([class.mem]/23). Mais la séquence initiale commune n'est définie que pour deux structures de mise en page standard ([class.mem]/20), et il y a quelques règles pour ce qui est considéré comme une structure de mise en page standard ([classe]/7).). Récapitulatif:

  • La classe peut ne pas être polymorphe.

  • La classe ne doit pas avoir plus d'une classe de base avec le même type.

  • La classe peut ne pas avoir un membre non statique du type de référence.

  • Tous les membres non statiques de la classe ont le même contrôle d'accès.

  • Tous les membres non statiques, y compris les membres hérités, sont d'abord déclarés dans la même classe. Toutes les classes de base et les membres non statiques, y compris les membres hérités obéissent à toutes les règles ci-dessus, récursivement.Il existe des règles qui indiquent que le premier membre non statique d'une structure de mise en page standard a la même adresse que la structure, et que tous les membres non statiques d'une union de mise en page standard ont la même adresse de l'union . Mais si une combinaison de ces règles implique que deux objets du même type doivent avoir la même adresse, la structure/union contenant n'est pas standard-layout.

(Pour un exemple de cette dernière règle:

struct A {};   // Standard-layout 
struct B { A a; };  // Standard-layout (and &b==&b.a) 
union U { A a; B b; }; // Not standard-layout: &u.a==&u.b.a ?? 
struct C { U u; };  // Not standard-layout: U is not. 

)

Votre DerivedA et DerivedB sont à la fois standard mise en page, de sorte qu'ils sont autorisés à avoir une séquence initiale commune. En fait, cette séquence commune est le seul membre de chacun, de sorte qu'ils sont en fait entièrement compatibles avec la disposition (et pourraient donc faire partie d'une séquence initiale commune d'une autre paire de structures contenant les deux). Cependant, l'une des choses les plus délicates est la règle concernant tous les membres appartenant à la même classe. Si vous ajoutez un membre non statique à DerivedA et/ou DerivedB, même si vous ajoutez un membre du même type aux deux, les structures modifiées ne sont plus du tout standard, il n'y a donc pas de séquence initiale. Cela limite la plupart des raisons réalistes que vous auriez voulu utiliser l'héritage dans ce modèle.

+0

Est-ce que «membre» dans ce contexte (par exemple, dans _All membres non statiques y compris les membres hérités sont d'abord déclarés dans la même classe_) se référer uniquement aux membres de données (champs) ou également aux fonctions membres? – BeeOnRope

2

L'accès à la classe de base par l'un des membres contenant cette base est autorisé, à condition que les structures utilisées soient standard.

Dans l'exemple que vous avez fourni, les structures sont standard, vous pouvez donc accéder à la base via u.a ou u.b.