В C++11 появились три вида умных (интеллектуальных) указателей: std::unique_ptr, std::shared_ptr и std::weak_ptr. Они избавляют от заботы освобождать память и другие ресурсы (если с ними правильно обращаться).
struct Base
{
virtual void print() const noexcept
{
std::cout << "Base (const)" << std::endl;
}
virtual void print() noexcept
{
std::cout << "Base" << std::endl;
}
virtual ~Base() = default;
};
struct Derived : Base
{
virtual void print() const noexcept override
{
std::cout << "Derived (const)" << std::endl;
}
virtual void print() noexcept override
{
std::cout << "Derived" << std::endl;
}
};
Полиморфное поведение прекрасно работает и с типами, скрытыми за умными указателями. Пример для std::unique_ptr:
auto base{ std::make_unique<Base>() };
base->print();
auto derived{ std::make_unique<Derived>() };
derived->print();
Base
Derived
Пример для std::shared_ptr.
auto base{ std::make_shared<Base>() };
base->print();
auto derived{ std::make_shared<Derived>() };
derived->print();
Base
Derived
Вариант с std::shared_ptr интересен тем, что для него есть обёртки — преобразования типа.
Пример в повышающим приведением.
auto basePtr2Derived{ std::static_pointer_cast<Base>(derived) };
basePtr2Derived->print();
Derived
За умным указателем на класс Base скрывается объект класса Derived.
if (auto downcasted{ std::dynamic_pointer_cast<Derived>(basePtr2Derived) }; downcasted)
{
downcasted->print();
}
Derived
dynamic_cast в зависимости от того, как его вызывают, может возвращать nullptr или выбрасывать исключение std::bad_alloc. std::dynamic_pointer_cast является noexcept-функцией, поэтому в случае неудачи возвращает nullptr.
Добавить (или убрать) квалификатор const.
auto constBase{ std::const_pointer_cast<const Base>(base) };
constBase->print();
Base (const)
Как и reinterpret_cast, преобразование std::reinterpret_pointer_cast может быть опасно.
struct Fake
{
virtual void print() const noexcept;
//virtual void print() noexcept;
};
Обратите внимание, что в этом примере константная перегрузка функции Fake::print() не определена, а неконстантная версия даже не объявлена.
auto reinterpretedDerived{ std::reinterpret_pointer_cast<Fake>(derived) };
reinterpretedDerived->print();
Derived
Исходный код: smart-pointers.cpp.