简体   繁体   English

在c ++中,我如何从一个对象到一个静态成员?

[英]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: 假设我有一个名为Shape的基类,如下所示:

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

Shape derives some classes, say rectangle and triangle. Shape派生出一些类,比如矩形和三角形。 and these classes have a static member named identifier, like in the following example: 这些类有一个名为identifier的静态成员,如下例所示:

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: 也就是说,在Shape添加:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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