在 c++ 中,如何从对象获取到静态成员

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

本文关键字:对象 获取 静态成员 c++      更新时间:2023-10-16

所以我有以下问题:

假设我有一个名为 Shape 的基类,声明如下:

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

形状派生了一些类,比如矩形和三角形。 这些类具有一个名为 identifier 的静态成员,如以下示例所示:

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

现在还有另一个类,它实现了指向形状命名组的指针向量

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

现在我的问题是我如何为组实现读写。

我已经为三角形和矩形实现了>>和<<运算符,我想到的想法是使用标识符来确定对象类型,问题是标识符是静态的,所以我想知道在这种情况下我可以做到。

欢迎任何帮助。谢谢。

通常,如果要执行动态调度的操作,则必须使用虚函数。

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<<`.
}

然后在实现中:

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.
}

如果你想要一个简单的实现,也许像这样?

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

如果你想要一个更具可扩展性的答案,那么需要进行一些调整。

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<<`.
}

然后实现成为

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
}
如果我

理解正确,您的目标是在只有指向基类的指针并且不知道它是哪个派生类时读取派生类的静态成员。

这可以通过添加虚拟函数来访问该成员来解决。也就是说,在Shape中添加:

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

并在每个形状中添加

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

然后你可以得到这样的标识符

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