Функция возвращает разные типы

Учитывая базовую структуру и производные структуры, я хотел бы написать метод, который может возвращать любой из них в зависимости от некоторого ввода, например, от 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». Как я могу решить это?

0

Решение

string_to_struct всегда возвращает Base по значению (потому что вы просили об этом). Так как статический тип bb это Base, bb.name всегда относится к Base::name, И так как вы возвращаете по значению, динамический тип bb также всегда будет Base,

Вам нужно сделать две вещи, чтобы получить то, что вы хотите:

  1. Не возвращайте полиморфные объекты Base значение. Если они созданы в функции, лучшим возвращаемым значением будет std::unique_ptr<Base>, Причина: вам нужны ссылки или указатели, чтобы полиморфия работала.

  2. Не используйте доступы, основанные на статический тип объекта, такого как .name, Вы хотите использовать динамический тип из bb, что проще всего сделать с помощью виртуального метода, такого как:

    virtual std::string getName() const
    

    Это также более чистое решение, чем полагаться на (очень хрупкое) сокрытие имени.

4

Другие решения

В этом случае лучше всего использовать 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 ++ Доступ к производному члену класса из указателя базового класса

РЕДАКТИРОВАТЬ: Третий подход заключается в использовании объекта-оболочки внутри производных классов и метода виртуального получения. В настоящее время я не могу думать о недостатке — кроме того, чтобы быть уродливым.

0