Retrieve data from heterogeneous std::list

前端 未结 4 1759
孤城傲影
孤城傲影 2021-01-24 20:14

In the below code I am simply trying to experiment with a Heterogeneous std::list where I have stored three Derived class object in a list of type Base*. When retrieving data fr

相关标签:
4条回答
  • 2021-01-24 20:30

    Your cast (Derived1*)*itr is equivalent to a static_cast which states:

    If the prvalue of type “pointer to cv1 B” points to a B that is actually a subobject of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the result of the cast is undefined.

    So you have undefined behaviour because you are casting pointers that point at Derived2 and Derived3 objects to a Derived1*.

    The proper way to achieve this is to have std::string s; defined in Base and give it a constructor that takes a std::string argument. Then you can make the constructors of Derived1 to Derived3 call this constructor with the appropriate string argument.

    If you add any extra members to one of the Derived classes, you won't be able to access them through the polymorphic Base*. However, trying to do that is a sign of bad design. You should only be treating the objects that a Base* points at as though they were Base objects. That is, Base describes the interface for those objects.

    If you really need to do something that is derived class specific to an object pointed to a Base*, you can use a dynamic_cast:

    if (Derived1* p = dynamic_cast<Derived1*>(*itr)) {
      // This condition will only be true if the object pointed to by `*itr` really is a Derived1
    }
    
    0 讨论(0)
  • 2021-01-24 20:38
    #include <list>
    #include <vector>
    #include <iostream>
    #include <string.h>
    
    class Base;
    typedef std::list<Base*> any_list;
    
    class Base{
    public:
        virtual ~Base(){}
        virtual std::string getData()=0;
    };
    
    class Derived1 : public Base
    {
    public:
        std::string s;
        Derived1():s("D1"){}
        std::string getData()
        {
            return s;
        }
    };
    class Derived2 : public Base
    {
    public:
        std::string s;
        Derived2():s("D2"){}
        std::string getData()
        {
            return s;
        }
    };
    class Derived3 : public Base
    {
    public:
        std::string s;
        Derived3():s("D3"){}
        std::string getData()
        {
            return s;
        }
    };
    
    int main(int argc, char **argv) {
        any_list l;
        l.push_back(new Derived1);
        l.push_back(new Derived2);
        l.push_back(new Derived3);
    
        for(any_list::iterator itr=l.begin();itr!=l.end();++itr)
            std::cout<<((Base*)*itr)->getData()<<std::endl;
    }
    

    Thanks for the help. Confusion is clear and the problem is solved. By d way what is -

    typedef std::list< std::unique_ptr > any_list;

    I didn't find anything called unique_ptr in std:: namespace. :(

    0 讨论(0)
  • 2021-01-24 20:44

    Easiest way might be to define Base like so:

    class Base {
    public:
        virtual const std::string& getData() = 0;
    }
    

    And then have your various derived classes implement getData() as appropriate. That way, your output loop could just be:

    for (Base* b : l) {
        cout << b->getData();
    }
    
    0 讨论(0)
  • 2021-01-24 20:50

    I would redefine Base to have a virtual method to output the information:

    class Base {
        friend std::ostream & operator << (std::ostream &os, const Base &b) {
            b.print(os);
            return os;
        }
        virtual void print (std::ostream &os) const = 0;
    public:
        virtual ~Base () {}
    };
    

    You are then forced to implement a print method in each derived class. Your print loop would look like:

        for (any_list::iterator itr=l.begin();itr!= l.end();++itr)
            std::cout << **itr;
    

    Your list should avoid managing bare pointers, since you put yourself at risk of leaking memory. You can use a smart pointer instead:

    typedef std::list< std::unique_ptr<Base> > any_list;
    

    Since unique_ptr requires explicit construction from the pointer, your code that populates the list needs to be updated.

        l.push_back(std::unique_ptr<Base>(new Derived1));
        l.push_back(std::unique_ptr<Base>(new Derived2));
        l.push_back(std::unique_ptr<Base>(new Derived3));
    
    0 讨论(0)
提交回复
热议问题