2009-10-09 6 views
0

Lorsque je compile le code suivant, je ne vois l'erreur au cours d'exécution qui dit « Impossible de jeter l'objet de type « Foo1 » taper « foo2 » »Pourquoi une erreur d'exécution lors du lancement de l'objet de classe de base vers un objet de classe dervied?

Pourquoi le compilateur ne montre pas cette erreur lors de compiler le temps?

public void Start() 
{ 
    Foo1 objFoo1 = new Foo1(); 
    Foo2 objFoo2 = (Foo2)objFoo1; 

    //objFoo1.FooA = 10; 
    //Console.WriteLine(objFoo2.FooA); 

} 

public class Foo1 {} 
public class Foo2 : Foo1 {} 
+0

Désolé. Je ne suis pas capable de formater correctement le bloc de code. Pourquoi devinez-vous? – csharpbaby

+0

ok. J'ai utilisé le formateur de code. maintenant le code semble bien :) – csharpbaby

+0

Désolé, nous avons essayé de vous aider à formater le code après avoir lu votre premier commentaire. – David

Répondre

2

Le compilateur est pas assez intelligent pour savoir que objFoo1 est vraiment un Foo1 simple. Il n'analyse pas suffisamment votre code source pour le déterminer. Tout ce qu'il voit est que objFoo1 est un Foo1, Foo2 est dérivé de Foo1, et donc la distribution est légal. Si à la place vous changiez cela en (int) objFoo1, il bombarderait au moment de la compilation puisque le compilateur pourrait voir qu'il n'y a aucun moyen de transformer un Foo1 en un entier. Imaginez qu'il y avait 1000 lignes de code entre les deux déclarations, beaucoup d'entre elles effectuant diverses affectations à objFoo1. Le compilateur devrait faire beaucoup de travail pour essayer de déterminer quel objet est exactement dans objFoo1. En général, il ne sera pas toujours en mesure de le faire. Il est beaucoup plus facile pour le compilateur de prendre simplement les informations de type statique à leur valeur nominale et de supposer que objFoo1 est un type d'objet Foo1 mais pas plus. De cette façon, il ne rejette pas votre programme de test simple mais accepte un programme plus compliqué.

Ce n'est pas non plus le travail du compilateur de rejeter votre code, dans ce cas. Il est possible, bien qu'étant tiré par les cheveux, que vous essayiez intentionnellement de générer un ClassCastException en faisant une distribution illégale. Ce serait inhabituel mais pas illégal de le faire.

Le long de ces lignes, il existe d'autres cas où l'analyse de code statique du compilateur peut être trompée. Cela ne parviendra pas à compiler:

return; 
System.out.println("hello world!"); // compile error - unreachable code 

Bien que cela compilera bien même si elle est sémantiquement identique:

if (true) return; 
System.out.println("hello world!"); 
-1

parce que le compilateur obéit à votre instruction de lancer. Cela permettra ensuite de compiler le code.

Foo2 objFoo2 = (Foo2)objFoo1; 

Si vous ne le forcez pas, cela vous donnera une erreur de compilation.

Foo2 objFoo2 = objFoo1; // kaboom 

Quoi qu'il en soit, la vraie raison est que votre instanciation de l'objet Foo1, qui est la base de foo2, mais pas foo2.

si vous le faites de cette façon, cela fonctionnera

Foo1 foo1 = new Foo2(); 
Foo2 foo2 = foo1 as Foo2; 
1

Il n'y a pas d'erreur de compilation car il est possible que votre code pourrait fonctionner depuis objFoo1 pourrait en fait être de type Foo2 - le compilateur ne sait tout simplement pas, car au moment de l'exécution, le type réel de l'objet pourrait différer.

Rappelez-vous que le polymorphisme vous permet de référencer des types dérivés comme des exemples de leurs types de base - le compilateur connaît et prend soin seulement sur le type déclaré de la référence - dans ce cas, la référence indique une distribution potentiellement valide il est permis.

0

Foo2 est un Foo1. Foo1 n'est pas un Foo2 mais c'est ce que le casting essaie d'affirmer. L'analogie de la vie réelle est la suivante: typiquement, les enfants héritent de l'argent de leurs parents, mais les parents n'héritent pas de l'argent de leurs enfants.

Je ressens votre douleur ici. Quand j'ai commencé la POO, j'ai rencontré beaucoup de problèmes de ce genre et il m'a fallu un certain temps pour comprendre certaines nuances. Si j'ai un Foo1 et que je veux qu'il ait les fonctionnalités supplémentaires, pourquoi ne puis-je pas lancer dans l'autre sens et gagner ces propriétés et méthodes supplémentaires? Malheureusement, ce n'est pas comme ça que ça fonctionne. Cela devient plus facile avec le temps et la pratique.

Questions connexes