Создание постоянного члена share_ptr

#c #boost #initialization #shared-ptr #member

#c #повышение #инициализация #общий-ptr #Участник

Вопрос:

У меня есть несколько классов, которые являются производными от чистой виртуальной базы:

 class base {
public:
    virtual int f() = 0;
};

class derived_0 : public base {
public:
    int f() {return 0;}
};

class derived_1 : public base {
public:
    int f() {return 1;}
};
  

Для краткости я ввел только два производных класса, но на практике у меня их больше.

И я хотел бы создать класс, который имеет постоянный общий указатель на базу. Я хотел бы выполнить следующее, но я не могу, поскольку я должен инициализировать указатель const в списке инициализации:

 class C{
public:
    C(bool type) { 
        if(type) {
            derived_0* xx = new derived_0;
            x = shared_ptr<base>( xx );
        }
        else {
            derived_1* xx = new derived1;
            x = shared_ptr<base>( xx );
        }
    } 
private:
    const share_ptr<base> x;
};
  

Как я могу получить эту функциональность?

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

1. Вы забыли пометить base::f() как virtual

2. Интересно, что именно представляют собой сообщения об ошибках.

Ответ №1:

Вы инкапсулируете создание объекта в функцию, например:

 shared_ptr<base> create_base(bool type) {
     if(type) {
         return make_shared<derived_0>();
     }
     else {
         return make_shared<derived_1>();
     }
}
  

А затем вы можете использовать его в своем списке инициализации:

 class C{
public:
    C(bool type)
    : x(create_base(type))
    {}
private:
    const share_ptr<base> x;
};
  

Ответ №2:

В простых случаях, подобных этому точному примеру:

 class C
{
    shared_ptr<Base> const x;
public:
    C( bool type ) 
        : x( type
            ? static_cast<Base*>( new Derived_0 )
            : static_cast<Base*>( new Derived_1 ) )
    {
    }
};
  

(И да static_cast , или, по крайней мере, один из них необходим.)

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

 class C
{
    shared_ptr<Base> const x;
    static shared_ptr<Base> makeSharedPtr( bool type );
public:
    C( bool type )
        : x( makeSharedPtr( type ) )
    {
    }
};
  

Это позволит использовать любую мыслимую логику (а также более сложный набор
параметров).

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

1. Обратите внимание, что в вашем первом случае с троичным оператором static_cast подобное использование означает, что деструктор должен быть виртуальным. Если вы вместо этого создадите временный shared_ptr указатель, сам указатель может сохранить точный производный класс для последующего удаления.

2. @MarkB Но в целом, если класс полиморфный, вы хотите, чтобы деструктор был виртуальным.