简体   繁体   中英

In c++, how can I get from an object to a static member?

So i have the following problem:

Suppose i have a base class named Shape declared like so:

class Shape
{
public:
    virtual void output(std::ostream &) const = 0;
}

Shape derives some classes, say rectangle and triangle. and these classes have a static member named identifier, like in the following example:

class Rectangle: public Shape
{
public:
    static const std::string identifier;
}

Now there is another class that implements a vector of pointers to shape named group

class Group : public Shape
{
  private:
      std::vector<Shape *> continut;
  public:
      static const std::string identifier;
      void output(std::ostream &) const;
}

Now my problem is how can I implement a read and write for the group.

I have implemented the >> and << operator for both triangle and rectangle and the idea that comes to mind is using the identifier to figure out the object type, the problem is that the identifier is static so I would like to know that I can do in this situation.

Any help is welcome. Thank you.

Usually, if you want to do an operation with dynamic dispatch, you have to use virtual functions.

class Shape
{
    virtual ~Shape() {} //ALWAYS HAVE THIS IF YOU HAVE VIRTUAL FUNCTIONS
    virtual void read(std::istream&) =0;
    virtual void write(std::ostream&) const =0;
public:
    virtual void output(std::ostream &) const = 0;

    friend std::istream& operator>>(std::istream& in, Shape& sh)
    {sh->read(in); return in;}
    friend std::ostream& operator<<(std::ostream& out, const Shape& sh)
    {sh->write(out); return out;}
};

class Rectangle: public Shape
{
    virtual void read(std::istream&);
    virtual void write(std::ostream&);
public:
    static const std::string identifier;
    //does not need (and probably should not have) `operator>>` and `operator<<`.
};

class Group : public Shape
{
    virtual void read(std::istream&);
    virtual void write(std::ostream&);
  private:
      std::vector<Shape*> continut;
  public:
      static const std::string identifier;
      void output(std::ostream &) const;
     //does not need (and probably should not have) `operator>>` and `operator<<`.
}

And then in the implementation:

void Group::write(std::ostream& out) 
{
    //simply calls write for each shape with no separator
    //you might want a separator
    for(Shape* p : continut)
        p->write(out);
}

void Group::read(std::istream& in) 
{ 
    //read is far more complicated
    //but without knowing the IO format, I can't really help you much.
}

If you want a simple implementation, maybe like this?

void Group::read(std::istream& in) 
{ 
    std::string shapename;
    while(in >> shapename) 
    {
        Shape* newshape = null;
        if (in == "triangle") 
            newshape = new triangle();
        else if (in == "square") 
            newshape = new square();
        else if (in == "rectangle") 
            newshape = new rectangle();
        else
            throw std::runtime_error(in + " is not a known shape!");

        newshape->read(in);
        continut.push_back(newshape);
    }
}

If you want a more scalable answer, then some adaptions need to be made.

class Shape
{
    virtual ~Shape() {} //ALWAYS HAVE THIS IF YOU HAVE VIRTUAL FUNCTIONS
    virtual void read(std::istream&) =0;
    virtual void write(std::ostream&) const =0;
    //this stores functionoids that create the different shape types
    typedef std::function<shape*(std::istream&)> named_ctor;
    std::unordered_map<std::string, named_ctor> virtual_constructors;
public:
    bool register_type(std::string name, named_ctor func)  
    {constructors[std::move(name)] = std::move(func); return true;}

    virtual void output(std::ostream &) const = 0;

    friend std::istream& operator>>(std::istream& in, Shape& sh)
    {sh->read(in); return in;}
    friend std::ostream& operator<<(std::ostream& out, const Shape& sh)
    {sh->write(out); return out;}
};

class Rectangle: public Shape
{
    virtual void read(std::istream&);
    virtual void write(std::ostream&);
    static shape* from_stream(std::ostream& in) {
        shape s = new Rectangle();
        s->read(in);
        return s;
    };
    static const bool registered = register("Rectangle", from_stream);
public:
    static const std::string identifier;
    //does not need (and probably should not have) `operator>>` and `operator<<`.
};
class Group : public Shape
{
    virtual void read(std::istream&);
    virtual void write(std::ostream&);

    static shape* from_stream(std::ostream& in) {
        shape s = new Group();
        s->read(in);
        return s;
    };
    static const bool registered = register("Group", from_stream);

     std::vector<Shape*> continut;
  public:
      static const std::string identifier;
      void output(std::ostream &) const;
     //does not need (and probably should not have) `operator>>` and `operator<<`.
}

And then the implementation becomes

void Group::read(std::istream& in) 
{ 
    std::string shapename;
    std::vector<Shape*> temp;
    while(in >> shapename) 
    {
        auto it = virtual_constructors.find(shapename); 
        if (it == virtual_constructors.end())
            throw std::runtime_error(in + " is not a known shape!");

        named_ctor& ctor = it->second;
        Shape* newshape = ctor(in);
        temp.push_back(newshape);
    }
    continuit = std::move(temp); //one step closer toward exception safety
}

If I understand correctly, your goal is to read the static member of the derived class when only having a pointer to the base class and no knowledge about which derived class it is.

This can be solved by adding a virtual function to access that member. That is, in Shape add:

virtual std::string getID() const = 0;

and in each shape add

virtual std::string getID() const { return identifier; }

Then you can get the identifier like

std::string id = continut[0]->getID();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM