Проблемы с использованием unique_ptr в качестве типа вектора (C++)

Я пытаюсь понять код C++, в котором используется вектор, в котором хранится unique_ptr<Base>, где Base — базовый класс и имеет производный класс Derivate.

При вставке unique_ptr<Derivate> в этот вектор ошибок нет и можно корректно вызвать метод производного класса.

Но при попытке изменить определенный атрибут Derivate возникает ошибка «ошибка: в 'базе класса' нет члена с именем 'deri_name'».

Код выглядит следующим образом:

#include<iostream>
#include<vector>
#include <memory>
using namespace std;

class Base
{
public:
    virtual void test(){
        cout << "this is Base test" << endl;
    }

};

class Derivate :public Base
{
public:
    Derivate(const string& name):deri_name(name){

    }
    virtual void test(){
        cout << "this is Derivate test by " << deri_name << endl;
    }

    string deri_name;
};

int main()
{
    vector<unique_ptr<Base>> vec;
    vec.push_back(make_unique<Derivate>("wayne"));

    vec[0]->test(); // will sprint "this is Derivate test by wayne"

    //vec[0]->deri_name = 'wong';  // will report an error " error: 'class Base' has no member named 'deri_name' "

    return 0;
}

Я пробовал некоторые методы, но, похоже, нет простого способа перевести vec[0] из unique_ptr<Base> в unique_ptr<Derivate>.

могу ли я изменить vec[0]->deri_name без изменения типа vec?

Учитывая, что unique_ptr<Base> на самом деле может не управлять Derivate (в этом случае принуждение компилятора к тому, чтобы вы действовали так, как будто это приведет к неопределенному поведению), почему вы хотите это сделать? Как правило, если у вас нет ОЧЕНЬ конкретной причины, необходимость/желание сделать что-то подобное обычно является признаком сломанного дизайна, и лучше исправить дизайн, чем пытаться заставить компилятор разрешить вам сделай это.

Peter 12.04.2023 05:49

«Кажется, нет простого способа преобразовать vec[0] из unique_ptr<Base> в unique_ptr<Derivate>» — вы не можете преобразовать unique_ptr<X> в unique_ptr<Y>, когда X != Y ни при каких обстоятельствах, поскольку они совершенно не связаны между собой. Однако вы можете построить unique_ptr<X> из unique_ptr<Y>, если Y происходит от X, и преобразовать необработанное X* в необработанное Y*, если Y происходит от X, или наоборот.

Remy Lebeau 12.04.2023 05:54
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вектор хранит указатели на Base, у которого нет члена с именем deri_name. Если вы уверены, что vec[0] указывает на Derivate объект, вы можете выполнить статическое приведение:

static_cast<Derivate&>(*vec[0]).deri_name = "wong";

Если вы не знаете наверняка, вы можете выполнить динамическое приведение:

if (auto ptr = dynamic_cast<Derivate*>(vec[0].get()))
    ptr->deri_name = "wong";

Поскольку такие вещи, как правило, доставляют неудобства, подумайте о том, чтобы ваш класс Base предоставлял виртуальные методы для операций, которые могут использовать производные классы. Например, метод set_name, который по умолчанию ничего не делает, но класс Derivate переопределяет.

Только вы знаете свои требования, но часто стоит подумать о том, как избежать загрязнения кода приведениями типов, если вы можете чисто реализовать что-то без этого.

Другие вопросы по теме