Подтвердить что ты не робот

С++ - преобразование указателя базового класса в указатель производного класса

#include <iostream>
using namespace std;

class Base {
public:
  Base() {};
  ~Base() {};
};

template<class T>
class Derived: public Base {
  T _val;
public:
  Derived() {}
  Derived(T val): _val(val) {}
  T raw() {return _val;}
};

int main()
{
  Base * b = new Derived<int>(1);
  Derived<int> * d = b;
  cout << d->raw() << endl;
  return 0;
}

У меня есть некоторая проблема полиморфизма прямо сейчас, и приведенный выше код суммирует все. Я создал указатель Base-класса, и я поместил в него указатель нового производного шаблона. Затем я создал новый указатель для производного класса шаблона, и я хочу, чтобы он имел ссылку, на которую указывает указатель базового класса. Хотя базовый указатель (b) указывает на Derived, ссылка не может быть передана указателю Derived класса (d), поскольку there no known conversion from Base * to Derived<int> * (как компилятор говорит).

Итак, есть ли трюк или альтернативный способ сделать это? Спасибо заранее.

4b9b3361

Ответ 1

Вы должны изменить базовый тип, который будет полиморфным:

class Base {
public:
    Base() {};
    virtual ~Base(){};
};

Чтобы отличить от некоторого супертипа к некоторому производному типу, вы должны использовать dynamic_cast:

Base *b = new Derived<int>(1);
Derived<int> *d = dynamic_cast<Derived<int> *>(b);

Использование dynamic_cast здесь проверяет, возможно ли это. Если нет необходимости делать эту проверку (потому что приведение не может завершиться неудачей), вы также можете использовать static_cast:

Base *b = new Derived<int>(1);
Derived<int> *d = static_cast<Derived<int> *>(b);

Ответ 2

Попробуйте следующее:

Derived<int> * d = static_cast<Derived<int>* >(b);

Недостатком является то, что вы можете использовать класс, являющийся экземпляром Base(), а затем d- > raw() будет undefined (segmentation fault likley). Если это так, используйте dynamic_cast и, по крайней мере, одну функцию ob base virtual (наличие виртуальных деструкторов необходимо при работе с полиморфизмом).

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

Ответ 3

Вы можете использовать dynamic_cast

Derived<int> * d = dynamic_cast<Derived<int> *>(b);

Если сбой броска (базовый указатель не указывает на запрошенный производный тип), он возвращает null.

Однако для работы dynamic_cast ваш базовый класс должен иметь хотя бы одну виртуальную функцию. Я предлагаю вам сделать виртуальный деструктор (это также предотвращает удаление других объектов другими потенциальными проблемами).

Использование dynamic_cast может указывать на плохой дизайн вашего кода.

Обратите внимание: если вы на 100% уверены, что базовый указатель указывает на ваш производный тип, вы можете заменить его static_cast, что немного быстрее. Лично я предпочитаю дополнительную проверку безопасности вообще.