Когда и почему вы выбрасываете объект? - PullRequest
6 голосов
/ 11 января 2011

Это считается корректной версией?

Derived d = new Derived();
Base b = d; // Always OK.

Зачем кому-то выпадать?Когда?Это потому, что мы должны превратить объект в базовый класс, чтобы у него не было функциональности производного класса?

Как этот код выглядит в памяти?Производный класс создает экземпляр, и для этого объекта создается память.Затем создается объект базового класса, который теперь ссылается на d.

Ответы [ 7 ]

9 голосов
/ 11 января 2011

Я думаю, вы можете быть немного озадачены тем, что делает upcast.Upcast не отключает функциональность производного объекта и не создает новый базовый объект.Скорее, это просто более ограниченный обзор объекта, который вы подняли.С помощью ссылки на базовый класс вы можете получить доступ только к тем методам, объявленным в Base, но если какой-либо из этих методов будет переопределен в производном классе, их вызов через базовую ссылку все равно вызовет производную версию.

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

3 голосов
/ 11 января 2011

Прогресс нормальный, потому что каждый Derived равен Base.

Когда вы пишете класс B, который наследуется от класса A, то B является подклассом A. Это означает, что вы можете использовать объект типа B в любом месте , что вы можете использовать объект типа A.

Вы должны прочитать о наследовании и насколько оно мощное.

1 голос
/ 11 января 2011

Это потому, что мы должны превратить объект в базовый класс, чтобы у него не было функциональности производного класса?

Поскольку есть какой-то фрагмент кода, который работает независимо от того, работает онВаш объект Derived1 или Derived2 и записан только исходя из предположения, что он поддерживает функциональность Base.Это называется абстракция и приведет к повторному использованию кода.Вам не нужно переписывать эту функцию для Derived1 и Derived2 отдельно.Вы абстрагируете детали, специфичные для Derived1 и Derived2.

Кстати, часто вы не выполняете приведение явно.Вы просто пользуетесь этим фактом, когда передаете экземпляр функции.Например, когда вы добавляете string к ArrayList, вы неявно приводите его к базовому типу object, поскольку подпись для Add:

void Add(object o);
1 голос
/ 11 января 2011

Если вы хотите использовать polymorphism, вы можете использовать upcast, например, у вас есть метод, который принимает Base, но вам нравится вызывать его с помощью Derived:

public void DoAction(Base base)
{
 // do stuff
}

DoAction(drivedItem);

DoAction(baseItem);

оба вышеприведенных вызова верны.

но в полиморфизме вы не можете использовать downcasting, вы можете использовать, например, перегрузку метода для преодоления ваших проблем.

0 голосов
/ 11 января 2011

Причина первая : Если в 2008 году я напишу код, который знает о классе Base и будет делать с ним некоторые вещи, которые касаются только функций этого класса, апскейтинг позволяет создать класс Derivedв 2011 году и передать экземпляр в мой код без каких-либо изменений.

Возможно, это также может быть сделано (и, возможно, более эффективно), если бы я сначала написал свой код с использованием обобщений.

Причина вторая : если вам нужно хранить несколько экземпляров разных классов в одном контейнере, вам нужно выгрузить эти экземпляры в общий базовый класс.Рассмотрим, например, список «загружаемых в настоящее время» источников данных, которые могут быть локальными файлами, URL-адресами, данными в памяти и даже сокетами - все это будут конкретные классы, совместно использующие общий класс источника данных.

0 голосов
/ 11 января 2011

Что касается вашего второго вопроса (как они выглядят в памяти), они оба выглядят одинаково в стеке. В стеке они оба являются простыми указателями на кучу.

0 голосов
/ 11 января 2011

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

void Test()
{
   Derived d = new Derived();
   this.DoSomething(d);
}

void DoSomething(Base b)
{
   // something
}

В этом случае d не «превращается» в Base объект, он просто обрабатывается как один. Я не знаю точно, но я думаю, что фактическая память, связанная с объектом d, не меняется вообще.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...