Каков синтаксис make_unique для указателя базового типа на производный объект?

#c #smart-pointers

#c #интеллектуальные указатели

Вопрос:

Рассмотрим следующие базовые и производные классы.

 class base
{
public:
    int i{9};
    virtual void func()
    {
        cout << "base" << endl;
    }
    virtual ~base()
    {

    }
};

class derived : public base
{
public:
    int i{4};
    void func()
    {
        cout << "derived" << endl;
    }

};
  

Я хотел бы создать unique_ptr тип base для derived объекта. Я знаю, что могу сделать

std::unique_ptr<base> ptr{new derived};

но когда я делаю

 auto ptr = std::make_unique<base>(derived{});
ptr->func();
  

это выводит base , что не является моим предполагаемым поведением. Какой правильный способ использовать std::make_unique в этом случае? Кроме того, почему auto ptr = std::make_unique<base>(derived{}) делает?

Ответ №1:

Когда вы делаете

 auto ptr = std::make_unique<base>(derived{});
  

make_unique<base> собирается создать unique_ptr<base> что означает, что он собирается создать только base объект. Поскольку derived является производным от base, законно передавать это в base конструктор копирования, чтобы код компилировался, но у вас есть base , а не derived .

Что вам нужно, так это

 std::unique_ptr<base> ptr = std::make_unique<derived>();
  

чтобы получить base указатель, который указывает на derived объект. Это не тот синтаксис, который вам нужен, но он работает правильно.

Если вы использовали

 auto ptr = std::make_unique<derived>();
  

тогда ptr было бы std::unique_ptr<derived> , а не std::unique_ptr<base> .

Комментарии:

1. Ах, я понимаю. В auto ptr = std::make_unique<base>(derived{}); я думал, что временное derived{} сообщение будет перенаправлено в unique_ptr конструктор. Это не тот случай, иначе эта строка сделала бы то, что я хотел, чтобы она делала?

2. @roulette01 Он пересылается конструктору, просто, поскольку вы использовали std::make_unique<base> , он будет смотреть только на base конструкторы для создания base объекта. Поскольку он derived является производным от base , он может вызывать base конструктор base(const baseamp;) ,, который компилятор неявно сгенерировал. Это разбивает производный объект только на базовую часть.