Почему только ошибка времени выполнения при приведении объекта базового класса к объекту класса dervied? - PullRequest
0 голосов
/ 09 октября 2009

Когда я компилирую следующий код, я вижу только ошибку во время выполнения, которая говорит "Невозможно привести объект типа 'Foo1' к типу 'Foo2'"

Почему компилятор не показывает эту ошибку во время компиляции?

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    {}

Ответы [ 4 ]

2 голосов
/ 09 октября 2009

Компилятор не достаточно умен, чтобы знать, что objFoo1 действительно прост Foo1. Он не анализирует ваш исходный код достаточно глубоко, чтобы определить это. Все, что он видит, это то, что objFoo1 является Foo1, Foo2 является производным от Foo1, и поэтому приведение является законным. Если вместо этого вы измените это значение на (int) objFoo1, оно будет бомбить во время компиляции, так как компилятор может увидеть, что нет никакого способа превратить Foo1 в целое число.

Представьте, что между этими двумя объявлениями было 1000 строк кода, многие из которых выполняли различные присваивания objFoo1. Компилятору придется проделать большую тяжелую работу, чтобы попытаться определить, какой именно объект находится в objFoo1. В общем, это не всегда можно сделать. Компилятору гораздо проще просто взять статическую информацию о типе по номиналу и предположить, что objFoo1 - это некоторый тип объекта Foo1, но не более. Таким образом, она не отвергает вашу простую тестовую программу, но принимает более сложную.

В этом случае компилятор также не должен отклонять ваш код. Возможно, хотя и заведомо надуманным, что вы намеренно пытаетесь сгенерировать ClassCastException, выполняя незаконное приведение. Это было бы необычно, но не противозаконно.

Вдобавок к этому есть и другие случаи, когда статический анализ кода компилятора можно обмануть. Это не удастся скомпилировать:

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

Хотя это скомпилируется нормально, хотя семантически идентично:

if (true) return;
System.out.println("hello world!");
1 голос
/ 09 октября 2009

Нет ошибки времени компиляции, так как возможно , что ваш код мог бы работать, поскольку objFoo1 может фактически иметь тип Foo2 - компилятор просто не знает, так как во время выполнения фактический тип объекта может отличаться.

Помните, что полиморфизм позволяет ссылаться на производные типы как на экземпляры их базовых типов - компилятор знает и заботится только о объявленном типе ссылки - в этом случае ссылка указывает на потенциально допустимое приведение так что это разрешено.

0 голосов
/ 26 февраля 2010

Foo2 - это Foo1. Foo1 не Foo2, но это то, что актеры пытаются утвердить. В реальной жизни аналогия такова: обычно дети наследуют деньги от своих родителей, но родители не наследуют деньги от своих детей.

Я чувствую вашу боль здесь. Когда я впервые начал ООП, я столкнулся с множеством подобных проблем, и мне потребовалось время, чтобы обдумать некоторые нюансы. Если у меня есть Foo1, и я хочу, чтобы он получил дополнительные функции, почему я не могу просто привести в другом направлении и получить эти дополнительные свойства и методы? К сожалению, это не так. Хотя со временем и практикой это становится легче.

0 голосов
/ 09 октября 2009

потому что компилятор подчиняется вашей инструкции приведения. Затем он позволит скомпилировать код.

Foo2 objFoo2 = (Foo2)objFoo1;

если вы не форсируете его, это даст вам ошибку компиляции.

Foo2 objFoo2 = objFoo1; // kaboom

В любом случае, настоящая причина в том, что вы создаете экземпляр объекта Foo1, который является основой Foo2, но не Foo2.

если вы сделаете это таким образом, это будет работать

Foo1 foo1 = new Foo2();
Foo2 foo2 = foo1 as Foo2;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...