полиморфизм — C ++ полиморфное клонирование: как получить производный указатель из базового указателя?

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

У меня есть вектор Base * и есть разные Derived<T> классы, которые происходят от Base. Различные параметры класса T объявляются в начале с предварительным объявлением. Что мне нужно, это взять пару объектов из этого vector<Base *> и применить function(Derived<T1> obj1, Derived<T2> obj2) использование шаблонов для того, чтобы сделать какую-то двойную отправку. Однако я не могу преобразовать указатель на базу в указатель на производное, когда я беру элемент из вектора. Таким образом, я не могу использовать function(Derived<T1> obj1, Derived<T2> obj2),

Конечно, это может быть просто достигнуто с помощью dynamic_cast<Derived<T> *>(base_ptr), Тем не менее, это не то, что я хочу, так как для этого нужно знать T заранее, что здесь не так. Я должен быть в состоянии выбрать любые элементы из вектора, не зная их Derived<T> тип.

Поэтому я попробовал полиморфное клонирование. Хотя он использует ковариантные типы возвращаемых данных, к сожалению, он не работает. Причина, как объясняют разные люди в SO и согласно стандарту C ++, заключается в том, что во время компиляции компилятор все еще не знает полный тип объекта. Таким образом, хотя ожидается, что clone () должен вернуть Derived<T> *, он возвращает Base *,

Несколько следующих строк кода выражают то, что я имею в виду.
В общем, полиморфное клонирование используется в следующем случае:

Base *b1 = new Derived;
Base *b2;
b2 = b1->clone();

Это не то, что я хочу. Мне нужен указатель на производное:

Base *b1 = new Derived;
Derived *d1;
d1 = b1->clone(); // This is what I want, but it fails.

Здесь компилятор жалуется, говоря, что объект типа Base * не может быть назначен объекту типа Derived *, Следовательно, я не могу использовать *d1 в function(,),

Я также попробовал метод не виртуального интерфейса (NVI), но он не работал.

Кто-нибудь имеет представление о том, как решить простой код выше, в частности, последнюю строку? Спасибо заранее.

2

Решение

То, что вы хотите, не возможно, так как нет никакой гарантии, что объект, на который указывает Base * на самом деле является примером Derived,

Максимум, что вы можете сделать, это использовать ковариантные типы возвращаемых значений для вашего clone() функция.

class Base
{
public:
virtual Base* clone() const
{
return new Base(*this);
};
virtual ~Base() {};
};

class Derived : public Base
{
public:
virtual Derived* clone() const    // note different return type
// this does override the inherited version
{
return new Derived(*this);
}
};int main()
{
Base *b = new Derived;
Derived *d1 = b->clone();    // this does not work

Derived *o = new Derived;
Derived *d = o->clone();    // this works
}

Если вы хотите клонировать из Base * к Derived *необходимо выполнить проверку во время выполнения и форсировать преобразование типов.

Base *b = new Derived;

Base *temp = b->clone();
Derived *d = dynamic_cast<Derived *>(temp);
if (d)
{
// d is actually an instance of Derived so can be used as such
}
else
{
//  The cloning did not produce a Derived.  Cope with it
}
delete temp;   // this will delete the object pointed to by d, since it is the same object

Как правило, однако, то, что вы спрашиваете, является положительным индикатором некорректного дизайна. В общих чертах (при условии, что вам нужна иерархия классов с полиморфной основой), вам нужно спроектировать Base поэтому его интерфейс (в частности, набор виртуальных функций, которые могут быть специализированы производными классами) достаточен для того, чтобы все пользователи класса могли делать то, что им нужно. Все пользователи Base должен быть указатель или ссылка на Base (т.е. Base & или Base *), и не должно быть необходимости их Base в Derived, Посмотрите «Принцип замещения Лискова» для получения дополнительной информации.

3

Другие решения

Я думаю, что в этом случае вы должны сделать кастинг. Вы можете узнать больше о static_Cast и reinterpret_cast. Вот несколько ссылок: Как заставить неявное преобразование в полиморфизм, Правильный способ приведения типов указателей

0