Учитывая базовую структуру и производные структуры, я хотел бы написать метод, который может возвращать любой из них в зависимости от некоторого ввода, например, от int, строки и т. Д.
До сих пор я пробовал различные фрагменты кода, такие как:
struct Base {
std::string name = "Base";
};
struct Derived1 : Base {
std::string name = "Derived1";
};
struct Derived2 : Base {
std::string name = "Derived2";
};
template<class T>
T string_to_struct(std::string s) {
if(s== "Derived1") {
return Derived1();
} else if(s == "Derived2") {
return Derived2();
} else {
return Base();
}
}
В основном я называю функцию:
void test2() {
std::string s = "Derived1";
auto bb = string_to_struct<Base>(s);
std::cout << bb.name << std::endl;
}
Теперь я ожидал бы напечатать «Derived1», если s соответствует «Derived1», «Derived2», если он равен «Derived2» и так далее. Однако приведенный выше код не работает, и string_to_struct в любом случае возвращает экземпляр «Base». Как я могу решить это?
string_to_struct
всегда возвращает Base
по значению (потому что вы просили об этом). Так как статический тип bb
это Base
, bb.name
всегда относится к Base::name
, И так как вы возвращаете по значению, динамический тип bb
также всегда будет Base
,
Вам нужно сделать две вещи, чтобы получить то, что вы хотите:
Не возвращайте полиморфные объекты Base
значение. Если они созданы в функции, лучшим возвращаемым значением будет std::unique_ptr<Base>
, Причина: вам нужны ссылки или указатели, чтобы полиморфия работала.
Не используйте доступы, основанные на статический тип объекта, такого как .name
, Вы хотите использовать динамический тип из bb
, что проще всего сделать с помощью виртуального метода, такого как:
virtual std::string getName() const
Это также более чистое решение, чем полагаться на (очень хрупкое) сокрытие имени.
В этом случае лучше всего использовать static_cast. Соответствующий фрагмент кода будет выглядеть следующим образом:
Base* string_to_struct7(std::string s) {
if(s== "Derived1") {
return new Derived1();
} else if(s == "Derived2") {
return new Derived2();
} else {
return new Base();
}
а затем для дальнейшей обработки:
auto t = string_to_struct7(s);
auto bb7 = static_cast<Derived1*>(t);
std::cout << bb7->name<< std::endl;
что именно то, что я хочу иметь. Производные члены класса теперь могут быть адресованы напрямую.
Ответ Макса Лангофа, конечно же, также действителен. Использование просто Java-методов, подобных методам получения, работает, но имеет недостаток: они должны быть определены в каждом классе для каждого члена класса, что может быстро выйти из-под контроля.
Более подробную информацию также можно найти здесь: C ++ Доступ к производному члену класса из указателя базового класса
РЕДАКТИРОВАТЬ: Третий подход заключается в использовании объекта-оболочки внутри производных классов и метода виртуального получения. В настоящее время я не могу думать о недостатке — кроме того, чтобы быть уродливым.