Вы можете определить свою собственную функцию шаблона SmartPtrCast, которая выполняет что-то вроде:
template <typename DestT, typename SrcT>
inline SmartPtr<DestT> SmartPtrCast(const SmartPtr<SrcT> &src)
{
return SmartPtr<DestT>(static_cast<DestT*>(src.get()));
}
Затем, все, что вам нужно сделать изящно из А в Б, это:
SmartPtr<B> b = SmartPtrCast<B>(doSomething(foo));
Предостережение Emptor:
Это будет работать только в том случае, если на умный указатель, возвращаемый doSomething()
, ссылаются где-то еще, и он не уничтожается, когда выходит из области видимости. Судя по вашему примеру, это так, но это все же не так грациозно, и следует отметить, что два указателя не будут делиться счетчиками ссылок (поэтому, если один из них будет уничтожен, второй потеряет свои данные).
Лучшее решение - отсоединить один из указателей (если в SmartPtr есть метод отсоединения). Еще лучшее решение (если у вас нет метода отсоединения или вы хотите поделиться счетчиком ссылок), это использовать класс-оболочку:
template <typename SrcT, typename DestT>
class CastedSmartPtr
{
private:
SmartPtr<SrcT> ptr;
public:
CastedSmartPtr(const SmartPtr<SrcT>& src)
{
ptr = src;
}
DestT& operator* () const
{
return *(static_cast<DestT*> >(ptr.get()));
}
DestT* operator->() const
{
return static_cast<DestT*> >(ptr.get());
}
DestT* get() const
{
return static_cast<DestT*> >(ptr.get());
}
}
template <typename DestT, typename SrcT>
inline SmartPtr<DestT> SmartPtrCast(const SmartPtr<SrcT>& src)
{
return CastedSmartPtr<SrcT, DestT>(src);
}
Это будет использовать SmartPtr
для внутреннего использования (так что счетчик ссылок правильно используется) и static_cast
для внутреннего использования до DestT
(без влияния на производительность). Если вы хотите использовать dynamic_cast
, вы можете сделать это только один раз в конструкторе, чтобы избежать ненужных накладных расходов. Вы также можете добавить в обертку дополнительный метод, такой как конструктор копирования, оператор присваивания, метод отсоединения и т. Д.