Полиморфизм не работает так, как я думал? - PullRequest
2 голосов
/ 25 июня 2009

У меня есть суперкласс, который обрабатывает информацию об автомобилях. У меня есть подкласс, который обрабатывает конкретную информацию о наклейке для транзакции. У меня есть специальное переопределение в переводной картинке транзакции, которая используется для проверки определенных вещей перед тем, как можно установить переводную картинку #. Проблема, с которой я сталкиваюсь, заключается в том, что иногда мне нужно получить информацию об универсальном объекте декали и установить его в качестве моей транзакции. Например:

TransactionDecal myTransactionDecal = new TransactionDecal();
Decal myGenericDecal = new Decal();
myTransactionDecal = (TransactionDecal) myGenericDecal.getGenericDecal();

Но я получаю ошибку во время выполнения, говорящую мне, что я не могу приводить между типами. Что именно я делаю не так, и это правильный путь? Спасибо!

Ответы [ 6 ]

3 голосов
/ 25 июня 2009

Принцип замещаемости будет означать, что любой тип может быть замещен сам по себе или подтипом.

Здесь вы делаете обратное - вы пытаетесь сослаться на экземпляр супертипа в переменной подтипа (предполагая, что Decal является суперклассом, а TransactionDecal подклассом).

Это заблокировано, потому что существует наследование для специализации существующего класса, то есть для расширения интерфейса; в общем, замена суперкласса ограничит интерфейс, и это позволит выполнять вызовы методов (через ссылочный тип переменной), которые не реализованы в суперклассе.

1 голос
/ 25 июня 2009

Вы не можете сделать это, потому что вы бы преобразовали менее специализированный класс (Decal) в более специализированный класс (TransactionDecal). Это не может работать, так как теперь вы сможете вызывать методы в Decal, которые там не реализованы (просто подумайте о, возможно, недавно введенных переменных в TransactionDecal, которые используются новыми методами или переопределенными методами), которые они не могут существовать в случае с наклейкой.

0 голосов
/ 25 июня 2009

Это зависит от того, что вы хотите сделать с myTransactionDecal, особенно от того, нужны ли вам элементы данных TransactionDecal.Как насчет добавления конструктора?

TransactionDecal::TransactionDecal(const Decal &);

Или, может быть, просто переместите желаемую функциональность в Decal или в функцию, не являющуюся членом?

0 голосов
/ 25 июня 2009

Используя ваш пример, вот как можно реализовать полиморфизм:

// cast derived object as base object
Decal myGenericDecal = null;
TransactionDecal myTransactionDecal = TransactionDecal.GetTransactionDecal()
myGenericDecal = myTransactionDecal;

// cast base object to a derived object
TransactionalDecal newTransactionalDecal = null;
newTransactionalDecal = (TransactionalDecal)myGenericDecal;
0 голосов
/ 25 июня 2009

Это называется уныние. Это довольно хорошее краткое введение , когда все в порядке, а когда нет (в любом случае, в C #) ...

Animal a;
a = b;
Bird b = (Bird) a; // Okay

Этот код успешно скомпилируется. Во время выполнения оператор приведения выполняет проверку, чтобы определить, упомянутый объект действительно типа птица. Если это не так, время выполнения InvalidCastException повышен.

Но вам не нужно этого делать. Ваш производный тип должен иметь возможность делать все, что может делать ваш базовый тип. Если у вас есть базовый тип и вы хотите что-то, что может делать только производный тип, то вам лучше сделать экземпляр производного типа, чтобы сделать это! :)

Редактировать за комментарий: Нет причины, по которой вы не можете предоставить конструктор Derived, который берет экземпляр Base и строит вокруг него Derived (например, Derived вокруг конкретной базы) ...

public D(B b)
{
}

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

0 голосов
/ 25 июня 2009

Джереми объясняет, почему это не работает, на деньги.

Если вы хотите обойти эту проблему, вы можете сделать транзакции не наследовать от Decal, а вместо этого содержать экземпляр Decal. Таким образом, вы можете задать для внутреннего экземпляра общий перевод, не теряя при этом никаких данных транзакции.

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

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