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