4

有没有办法通过基类指针让派生类的通用代码访问成员?或者任何其他方式解决这个问题?

假设我有一个 Shape 类。我有继承它的类 Square 和 Triangle。两者都有自己的私有成员,它们彼此无关,因此将它们放在基类中毫无意义。现在,如果我需要将一个类写入文件,但直到我需要将其写入文件时才知道该类是方形还是三角形,该怎么办?

我一直在试图弄清楚如何解决这个问题。最坏情况的解决方案是将 Square 和 Triangle 的数据写入文件,为读写添加一个标识符(Triangle 或 Square),并在加载数据时让一个小型解析器将类放在一起。这将是低效且浪费时间的。

我想知道是否有一些技巧或设计模式或任何可以帮助解决这种情况的方法。

4

5 回答 5

8

这种序列化应该使用虚函数来完成。在应序列化对象的基类中定义一个函数。三角形和正方形覆盖了这个函数并写

  • 标识符
  • 所有应该序列化的数据

如果合适,您可以在基类中实现公共部分。

当您要加载文件时,您将需要创建与标识符对应的类实例的工厂方法。必须调用新的实例虚拟反序列化方法来加载实际数据。

于 2012-09-04T14:13:52.823 回答
3

您可以在基类中有一个纯虚拟吸气剂。并且您的所有派生类都将覆盖它。像这样

class Shape{
  public:
    virtual int data() const = 0;
};
class Square: public Shape{
  private:
     int _member;
  public:
    virtual int data() const{
     //do something with private members and return it
     return _member;
    };
};
于 2012-09-04T14:12:06.167 回答
1

我认为没有直接的方法可以消除这种开销。通常这是通过两件事来完成的。首先,对象需要一个序列化机制:

要序列化事物,需要一个位置来序列化。在这种情况下,我们将使用数据容器来执行此操作,但这也可以是文件流或容器类。序列化可以从对象内部或外部进行,现在最简单的实现是从内部进行:

简单的序列化部分:

class Shape{
public:
  virtual void serialize( Datacontainer &o ) const = 0;
};

class Triangle: public Shape{
  void serialize( Datacontainer &o ) const{
    o.add('T');
    o.add(corners);
  }
  std::vector<point> corners;
}

class Circle: public Shape{
  void serialize( Datacontainer &o ) const{
    o.add('C');
    o.add(center);
    o.add(radius);
  }
  point center;
  double radius;
}

在序列化过程中,您可以使用基本类 Shape 来做到这一点:

Shape *tri = new Triangle;
tri->serialize( dataContainer or file );

反序列化并不容易,因为您需要知道类型。一个很好的模式是Builder 模式。尽管如此,我们可以实现一个更可能的 C++ 方式来做到这一点:

将以下内容添加到您的所有课程中:

static Shape* createFrom( Datacontainer &o );

例如。圈子实现:

Shape* Circle::createFrom( Datacontainer &o )
{
  Circle *c = new Circle()
  c->center = o.get();
  c->radius = o.get();
}

这使我们能够创建一个具体的实例,但我们有该方法的通用函数足迹。现在可以实现一个非常简单的构建器,如下所示:

class ShapeBuilder
{
public:
  static Shape* createShape( Datacontainer& o )
  {
    char id = o.get();
    swith(id){
    case 'T':
      return Triangle::createFrom(o);
    case 'C':
      return Circle::createFrom(o);
    }        
  }
}
于 2012-09-04T15:51:46.607 回答
0

您需要在基类中声明虚拟方法,并让派生类定义它们。但是,如果您想将它们保存到文件中 - 您将需要一种方法来识别文件中的特定类实例,因为它们可能具有不同的内存布局。

于 2012-09-04T14:11:36.563 回答
0

可能最好的方法是做这样的事情。基本模式是您可以将公共代码(保证对于每个派生类始终相同)放在基类中。需要不同的东西,放入派生类各自实现不同的虚函数。

class Shape {
    virtual void writeSerialData(std::ostream &) const = 0;
  public:
    void writeToFile(const std::string &filename) const {
        std::ofstream outfile(filename); // filename.c_str() in C++03
        writeSerialData(outfile);
        if (!outfile.close()) {
            // report the error
        }
    }
    virtual ~Shape() {}
};

class Square : public Shape {
    double length;
    virtual void writeSerialData(std::ostream &out) const {
        out << "Square{" << length << '}';
    }
  public:
    Square(double l) : length(l) {}
};

现在你有下一个问题——你如何从文件中读回一个对象,而不事先知道它是哪个派生类?为此,您需要一种查看文本的方法,Square并且 (a) 调用Square知道如何解释数据的类的静态函数,或者 (b) 通过向其提供要解释的数据来实例化类 Square。在您走得太远之前,值得研究 Boost Serialization 或其他序列化库。

于 2012-09-04T14:28:47.950 回答