Imago
Imago

Reputation: 501

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?

Upvotes: 0

Views: 326

Answers (2)

Imago
Imago

Reputation: 501

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.

Upvotes: 0

Max Langhof
Max Langhof

Reputation: 23701

string_to_struct always returns a Base by value (because you asked for that). Since the static type of bb is a Base, bb.name always refers to Base::name. And since you return by value, the dynamic type of bb will also always be Base.

You would need to do two things to get what you want:

  1. Do not return polymorphic objects by Base value. If they are created in the function, the best return value would be a std::unique_ptr<Base>. Reason: You need references or pointers for polymorphy to work.

  2. Do not use accesses that rely on the static type of the object, such as .name. You want to use the dynamic type of bb, which is easiest to do with a virtual method such as:

    virtual std::string getName() const
    

    That is also a cleaner solution than relying on the (very brittle) name hiding.

Upvotes: 4

Related Questions