c++templatesvirtual-functionscovariant-return-types

Function return different types


Given a Base struct and Derived Structs, I would like to write a method that can return any of them depending on some input, for example on an int, string etc.

Thus far I tried out various code snippets, like the following:

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();
    }
}

In main I call the function:

void test2() {
    std::string s = "Derived1";
    auto bb = string_to_struct<Base>(s);
    std::cout << bb.name << std::endl;
}

Now I would expect to print "Derived1" if s is matches "Derived1", "Derived2"if it equals "Derived2" and so on. Above code however, does not work and string_to_struct returns in any case an instance of "Base". How can I solve this?


Solution

  • Best case in above scenario would be to use static_cast. The corresponding code snippet would then look like:

    Base* string_to_struct7(std::string s) {
        if(s== "Derived1") {
            return new Derived1();
        } else if(s == "Derived2") {
            return new Derived2();
        } else {
            return new Base();
        }
    

    and then for further processing:

    auto t = string_to_struct7(s);
    auto bb7 = static_cast<Derived1*>(t);
    std::cout << bb7->name<< std::endl;
    

    which is exactly, what I want to have. Derived class members can now be addressed directly.

    Max Langhof's answer is of course also valid. Using simply Java like getter methods works, but has the drawback they have to be defined in every class for every class member, which can get out of hand quickly.

    More information can be also found here: C++ Access derived class member from base class pointer

    EDIT: A third approach would be to use a wrapper object inside the Derived Classes and a virtual getter method. Currently I can't think of a drawback - apart from being ugly.