0

How can one access child class functions from a vector of a parent class without downcasting?

example:

class a {
 public:
  ...
};

class b : public a {
  double output() {  // both child class have memeber function called output,
                     // but they return different data type.
    return 0;
  }
};
class c : public a {
  bool output() { return false; }
};

// main
vector<a> vec;
b obj;
c obj2;
vec.push_back(obj);
vec.push_back(obj2);
for (int i = 0; i < vec.size(); i++) {
  cout << vec[i].output();
}

Error:

error: no member function called "output" found in a

I have tried function overridding:

class a{
public:
  auto output()
};

This approach don't work because I sometimes need to pass multiple parameters and this function doesn't allow that and will throw me the error: Function output expected 0 parameters, received x parameters.

David G
  • 94,763
  • 41
  • 167
  • 253
  • std::variant can be useful here – vsh Dec 25 '19 at 00:22
  • 2
    Your vector isn't storing `b` or `c` objects; it only stores `a`, so casting to something else would be undefined (see [object slicing](https://stackoverflow.com/questions/274626/what-is-object-slicing)). Possibilities include (virtual) functions with different names, returning a `std::string`, or having a virtual `output` function actually do the output. – 1201ProgramAlarm Dec 25 '19 at 00:26
  • 2
    Does this answer your question? [What is object slicing?](https://stackoverflow.com/questions/274626/what-is-object-slicing) – Richard Critten Dec 25 '19 at 00:26
  • so what other ways can i store those objects in a way where I can access them? – darren zou Dec 25 '19 at 00:28
  • 1
    @darrenzou if you want to store hierarchy common solution is storing a (smart) pointer to the base class. - `std::vector>` in your case – Slava Dec 25 '19 at 00:31
  • i got the error: no member named 'unique_ptr' in namespace 'std' – darren zou Dec 25 '19 at 00:40
  • 1
    `unique_ptr` can be found in the `` header if you are compiling to C++11 or a higher Standard revision. If you are compiling to C++14 or better, take advantage of `std::make_unique` as it removes a few failure cases that can result in memory leaks. – user4581301 Dec 25 '19 at 00:43
  • 2
    I would propose that if you need to access a member function of a derived class when you have a collection of (pointers to) parent classes, then your inheritance design needs more work, rather than the part of the code that tries to access the function. – JaMiT Dec 25 '19 at 00:50
  • 1
    A formalization of the point raised by @JaMiT: [The Liskov Substitution Principle](https://stackoverflow.com/questions/56860/what-is-an-example-of-the-liskov-substitution-principle). – user4581301 Dec 25 '19 at 00:53

1 Answers1

-2

It is possible like this

#include <iostream>
#include <vector>

struct result
{
    enum
    {
        BOOL,
        DOUBLE
    } tag;
    union ret {
        double d;
        bool b;
    } r;
};

std::ostream &operator<<(std::ostream &s, const result &r)
{
    switch (r.tag)
    {
    case result::DOUBLE:
        s << r.r.d;
        break;

    case result::BOOL:
        s << r.r.b;
        break;

    default:
        break;
    }
    return s;
}

class a
{
public:
    virtual result output() = 0;
};

class b : public a
{
    result output() override
    {
        result r{result::DOUBLE, 132.};
        return r;
    }
};
class c : public a
{
    result output() override
    {
        result r{result::BOOL, false};
        return r;
    }
};

int main(int argc, char const *argv[])
{
    std::vector<a *> vec;
    a *obj = new b;
    a *obj2 = new c;
    vec.push_back(obj);
    vec.push_back(obj2);

    for (int i = 0; i < vec.size(); i++)
    {
        std::cout << vec[i]->output() << std::endl;
    }
    return 0;
}

but its ugly. even more then

vsh
  • 301
  • 2
  • 10
  • 1
    Why does this work? Code-only answers tend to be rather unhelpful in the long run. – JaMiT Dec 25 '19 at 00:51
  • 2
    This is an interesting solution to the problem and I will be happy to remove the downvote when you highlight the changes you made and explain why you made them. – user4581301 Dec 25 '19 at 00:55
  • Base class declare virtual function to call which returns enum-tagged union, that can store different types of result and tag which this type is. In vector you store pointers to base class and then call parent class function. When you want to get the result you define tag and according to it read needed field in union. – vsh Dec 25 '19 at 01:00
  • 1
    You do not need to do ugly enum-tagged solution - there is `std::variant` with visitor pattern – Slava Dec 25 '19 at 02:20
  • 1
    @Slava I proposed variant in a first comment to question asked – vsh Dec 25 '19 at 02:22
  • At that point, one should either modify the virtual function to something like `virtual void OutputTo(std::ostream &s);` if he expect to have only a few function like that or use the visitor pattern if he has lot of such function but the class hierarchy is stable. I don't know much about `std::variant` but usually it is preferable to either use template or virtual function but not a mix of the 2. – Phil1970 Dec 25 '19 at 03:03