Question

J'ai trois classes:

class A {};

class B : virtual public A {};
class C : virtual public A {};

class D: public B, public C {};

Tenter une coulée statique de A * B * Je reçois le ci-dessous erreur:

cannot convert from base A to derived type B via virtual base A
Était-ce utile?

La solution

Pour comprendre le système de distribution que vous devez plonger dans le modèle objet.

La représentation classique d'un modèle simple de la hiérarchie est le confinement. Que si B dérive de A alors l'objet B contiendra en fait un sous-objet A à côté de ses propres attributs

Avec ce modèle, downcasting est une manipulation simple pointeur, par un décalage connu au moment de la compilation qui dépend de la mise en page de la mémoire de B.

est ce que static_cast faire:. Un casting statique est surnommé statique parce que le calcul de ce qui est nécessaire pour la distribution se fait à la compilation, que ce soit pointeur arithmétique ou conversions (*)

Cependant, lorsque des coups de pied de l'héritage virtual dans les choses ont tendance à devenir un peu plus difficile. Le principal problème est que l'héritage de virtual toutes les sous-classes partagent une même instance de la sous-objet. Pour ce faire, B aura un pointeur vers une A, au lieu d'un A approprié, et l'objet de classe de base A sera instancié en dehors de B.

Par conséquent, il est impossible au moment de la compilation pour pouvoir en déduire la moyenne arithmétique de pointeur nécessaire. Il dépend du type d'exécution de l'objet

Chaque fois qu'il ya une dépendance de type d'exécution, vous avez besoin RTTI (RunTime information Type), et en utilisant RTTI pour moulages est le travail de dynamic_cast .

En résumé:

  • compilation baissés: static_cast
  • baissés d'exécution: dynamic_cast

Les deux autres sont également des moulages à la compilation, mais ils sont tellement spécifiques qu'il est facile de se rappeler ce qu'ils sont pour ... et ils sont mauvais, alors il vaut mieux ne pas les utiliser du tout de toute façon.

(*) Comme l'a noté @curiousguy dans les commentaires, ce ne vaut que pour downcasting. Un static_cast permet indépendamment de l'héritage transtypage ascendant virtuel ou simple, mais alors le casting est également inutile.

Autres conseils

Pour autant que je sache, vous devez utiliser dynamic_cast parce que l'héritage est virtual et vous êtes downcasting.

Vous ne pouvez pas utiliser static_cast dans cette situation parce que le compilateur ne connaît pas le décalage de B par rapport à A au moment de la compilation. Le décalage doit être calculée à moment de l'exécution en fonction du type exact de l'objet le plus dérivé. Par conséquent, vous devez utiliser dynamic_cast.

Oui, vous devez utiliser un dynamic_cast, mais vous aurez à faire la classe de base A polymorphes, par exemple en ajoutant un dtor virtuel.

Selon docs standards,

Section 5.2.9 - 9 , Cast statique ,

  

Un rvalue de type « pointeur vers CV1 B », où B est un type de classe, peut être converti en un rvalue de type « pointeur vers CV2   D » où D est une classe dérivée (article 10) à partir de B, si une conversion standard valable à partir de « pointer à D » à « pointeur vers B »   existe (4.10), CV2 est le même cv-qualification, ou plus cv-qualification que, CV1, et B est ni une classe de base virtuelle   de D, ni une classe de base d'une classe de base virtuelle de D.

Par conséquent, il est impossible et vous devez utiliser dynamic_cast ...

  

5.2.9 $ / 2- « Une expression e peut être   converti explicitement à un type T en utilisant   un static_cast de la forme   static_cast (e) si la déclaration   « T t (e); » est bien formée, pour certaines   inventé variable temporaire t (8,5) ».

Dans votre code, vous essayez static_cast avec T = B * 'et 'e = A *'

B * t (A *) 'est pas bien formé en C ++ (mais 'A * t (B *)' est parce que 'A' est une base virtuelle non ambiguë et accessible de 'B'. Par conséquent, la code donne erreur.

Je ne sais pas si cela est « sûr » mais.

En supposant

B dérivé de A (A et virtuel pur)

Depuis que je SAIS qu'un pointeur B reste un pointeur vers B.

    class A
    {
            virtual void doSomething(const void* p) const =0;
    };

    class B
    {
    public:
            int value;
            virtual void doSomething(const void*p)const
            {
            const B * other = reinterpret_cast<const B*>(p);
            cout<<"hello!"<< other->value <<endl;
            }
    };

    int main()
    {
            B  foo(1),bar(2);
            A * p = &foo, q=&bar;
            p->doSomething(q);
            return 0;
    }

exécute du programme et retourner correctement l'impression « bonjour! » et la valeur de l'autre objet (dans ce cas « 2 »).

par la manière, ce que je fais est très dangereux je donne (personnellement un ID à chaque classe et j'affirme après réinterpréter coulée que ID courant est égal à un autre ID pour être sûr que nous faisons quelque chose avec 2 classes égales ) et que vous voyez que je me suis limité aux méthodes « const ». Ainsi, cela fonctionne avec les méthodes « non-const », mais si vous faites quelque chose de mal attraper le bug sera presque unpossible. Et même avec l'affirmation qu'il ya une chance sur 1 de 4 milliards pour réussir l'affirmation même quand il est censé à l'échec (Assertion (ID == Autre-> ID);)

Par ailleurs .. Une bonne conception OO ne devrait pas exiger ce peu de choses, mais dans mon cas, j'essayé de refactoring / re-concevoir le code sans être en mesure d'abandonner l'utilisation de la coulée de réinterpréter. d'une manière générale, vous pouvez éviter ce genre de choses.

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