2009-08-03 5 views
3

Voici main():Attraper les exceptions polymorphically

int main() 
{ 
    B b(1,"two","three"); 
    try 
    { 
     f1(b); 
    } 
    catch(B& b_ref) 
    { 
     cout<<"Caught B&"<<endl; 
     b_ref.print(); 
    } 
    catch(A& a_ref) 
    { 
     cout<<"Caught A&"<<endl; 
     a_ref.print(); 
    } 

    system("pause"); 
    return 0; 
} 

Voici f1():

void f1(A& subject) 
{ 
    throw subject; 
}  

Information:

B hérite de A. A::print() est virtuel et est réimplémenta B. capture qui attrape l'exception est catch(A& a_ref), ce qui, je suppose, est logique, puisque le type statique des exceptions (sujete ct) est A &. MAIS, pourquoi ne fonctionne pas B:: print()? Le type dynamique est-il "perdu"? Seul A::print() s'exécute dans la ligne a_ref.print();.

Quelqu'un peut-il expliquer?

+0

Wow cela est sorti totalement illisible. S'il vous plaît, regardez ici pour une version compréhensible de ce poste: http: //forums.devarticles.com/c-c-help-52/catching-exceptions-polymorphically-208759.html –

+0

J'ai reformaté votre question:> – arul

+0

Correction. N'oubliez pas de mettre en retrait le code avec 4 espaces ou mieux, sélectionnez le code et appuyez sur Ctrl + K – Aamir

Répondre

5

Lorsque vous dites "throw subject", un nouvel objet d'exception est créé en fonction du type statique de l'expression de lancement (subject). Le fait que subject soit une référence n'est pas pertinent pour déterminer l'objet à lancer. Un nouvel objet A est copié à partir de subject. Cette copie (ou éventuellement une copie de cette copie) est l'objet réel capturé.

6

throw ne lance qu'un objet du type de l'expression qui le suit. Dans ce cas, subject est de type A&, quel que soit l'objet réel, de sorte qu'un A est lancé (notez que les références ne peuvent pas être levées, donc une copie est faite).

Vous pouvez gérer cela en ajoutant une fonction membre à vos classes d'exception qui lève l'exception. Tant que vous implémentez cette méthode dans chaque classe, le remplacement qui est appelé connaît le type d'exécution de l'objet et peut throw *this.

http://www.ddj.com/cpp/184401940

+0

J'ai fait ce que vous avez dit et maintenant cela fonctionne comme prévu .. J'ai ajouté la fonction membre à A: virtual void raise() {throw *ce; } et ce membre fonctionne à B: void raise() {throw * this; } Alors maintenant, 'raise()' s'assure que je lance l'objet le plus dérivé référencé par A & subject, correct? C'est bizarre que personne ne nous ait jamais parlé de ça, seulement en ce qui concerne les pointeurs. Je suppose que la raison pour laquelle cela fonctionne avec des pointeurs est parce que, le pointeur lui-même est copié, et je peux toujours savoir à quoi il pointe dynamiquement .. –

+0

Exactement, oui. Cela fonctionne avec des pointeurs parce que le pointeur lui-même est l'objet lancé, alors que quand vous lancez en utilisant une référence, c'est le referand qui est lancé (et donc copié, et donc découpé). –

+0

Veuillez noter que vous devez être très prudent lorsque vous lancez des pointeurs. Si vous lancez des pointeurs sur des objets créés dynamiquement, il peut être extrêmement difficile d'obtenir une cohérence entre la sémantique de propriété. Lancez des pointeurs vers des objets locaux généralement incorrects et lancez des pointeurs vers des objets globaux ... eh bien, cela implique que vous avez des objets globaux. –

-1

Parce que vous attrapez par référence l'objet est «coupé en tranches.

Si vous voulez vraiment un comportement polymorphe, essayez d'utiliser quelque chose comme l'idiome de pimpl.

+0

Pas tout à fait vrai; c'est attraper par la valeur, pas la référence, qui cause le problème du «découpage», et ce n'est pas ce qui se passe ici. C'est plutôt que 'throw' ne considère pas le type réel de l'objet, juste le type statique. (voir la réponse de onebyone). –

-1

nvm, mon manque de compétences en compréhension de lecture. Pensé qu'il crée des objets de type A.

+0

Ceci est en arrière. Si print() est virtuel et que vous avez un pointeur A ou une référence à ce qui est réellement un B, alors B :: print est appelé. A :: print n'est appelé que si B :: print appelle explicitement la classe de base. –

4

Les blocs de saisie fonctionnent polymorphiquement, mais pas le lancer. Quand vous dites:

void f1(A& subject) 
{ 
    throw subject; 
} 

vous jetez un A, bien que la chose passée à la fonction est un B.

+0

C'est méchant (un problème de découpage s'appliquera). Apprendre quelque chose de nouveau chaque jour. –

6

Selon standard C++ 15.1/3:

A deux pas d'expression initialise un objet temporaire, appelé l'objet d'exception, dont le type est déterminé en supprimant les qualificatifs cv de haut niveau du type statique de l'opérande de lancer ...

Donc, vous créez un objet temporaire de type A, pas B.

+0

+1 pour avoir cité la norme – Bklyn

Questions connexes