有没有办法让通用代码通过基类指针访问派生类的成员?或者其他任何方式?
假设我有一个类Shape。我有继承它的Square和Triangle类。两者都有自己的私有成员,彼此无关,所以在基类中没有任何意义。 现在,如果我需要将一个类写入文件,但是我不知道该类是Square还是Triangle,直到我需要在文件中写入它?
我一直想弄清楚如何解决这个问题。最糟糕的解决方案是将Square和Triangle的数据写入文件,为读取和写入添加标识符(三角形或正方形),并在加载数据时使用一个小的解析器将类放在一起。这将是低效率和浪费时间。
我想知道是否有某些技巧或设计模式或任何可以帮助解决问题的方法。
答案 0 :(得分:8)
此序列化应使用虚函数完成。在基类中定义一个将序列化对象的函数。 Triangle和Square会覆盖此函数并编写
如果合适,您可以在基类中实现公共部分。
如果要加载文件,则需要使用工厂方法创建与标识符对应的类实例。必须调用新的实例虚拟反序列化方法来加载实际数据。
答案 1 :(得分: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;
};
};
答案 2 :(得分: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 );
反序列化并不那么容易,因为您需要知道类型。一个很好的模式是构建器模式。尽管如此,我们可以实现更多C ++可能的方法:
将以下内容添加到您的所有类中:
static Shape* createFrom( Datacontainer &o );
例如。 Circle实施:
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);
}
}
}
答案 3 :(得分:0)
您需要在基类中声明虚方法,并使派生类定义它们。如果你想将它们保存到文件中 - 你需要一种方法来识别文件中的特定类实例,因为它们可能有不同的内存布局。
答案 4 :(得分: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或其他序列化库。