如何在读取文件后构建不同对象的向量

时间:2009-11-07 00:51:28

标签: c++

大家好!我是C ++的新手,现在正在进行C ++项目。整个结构已经完成。但我一直想知道

如何构建不同对象的向量以及如何从一开始就读取文件。

在我的问题中,首先我必须阅读一个带有readObstacles(std :: istream& fs)的txt文件,其格式如下:

  

RECTANGLE 1 2.5 2 2 0.2
  CIRCLE 1 2.5 1.2
  RECTANGLE 4 2 2 2 0.3

(每个障碍开始一条新线)

我需要读取不同障碍物的数据信息并将这些障碍物存储在载体中 Class Obstacle是具有两个子类CIRCLE和RECTANGLE的基类 我尝试将这些不同的障碍(我认为应该有他们的数据信息)放在障碍物矢量中,然后调用他们都拥有的虚拟函数。

以下是我尝试使用的代码:

vector<Obstacle> obsdata; 

Myworld::readObstacles(std::istream &fs)
{
    std::string shape;
    double num1,num2,num3,num4,num5;
    while(fs>>shape>>num1>>num2>>num3>>num4>>num5)
    {
        if(shape=="CIRCLE") {
            CIRCLE c;
            c.m_Xc=num1;
            c.m_Yc=num2;
            c.m_Radius=num3;       
            obsdata.push_back(c);
        }

        if(shape=="RECTANGLE") {
            RECTANGLE r;
            r.center_x=num1;
            r.center_y=num2;    
            r.width=num3;
            r.height=num4;
            r.angle=num5;
            obsdata.push_back(r);
        }
    }
}

MyWorld::writeMatlabDisplayCode(std::ostream &fs)
{
    for( i = 0; i < obsdata.size(); i++ )
        obsdata[i].writeMatlabDisplayCode(fs);
}

我知道它不起作用,但我不知道该怎么做。

任何言语都会有所帮助。谢谢!

5 个答案:

答案 0 :(得分:2)

您遇到一个称为切片的问题:如果复制到包含基类实例的向量,则会丢失派生类中的数据。

您可以使用指向基础的指针向量:

std::vector<Obstacle*> obsdata;
RECTANGLE r = new RECTANGLE;
// set properties
obsdata.push_back(r);
// use it later, e.g.:
obsdata[0]->writeMatlabDisplayCode(fs);
// clean up when you don't need obstacles anymore:
for(std::vector<Obstacle*>::iterator it = obsdata.begin(); it != obsdata.end(); ++it)
    delete *it;

您还应避免每次尝试读取5个数字。相反,您可以阅读障碍物描述,然后阅读与特定障碍物需要的数量相同的数字。

答案 1 :(得分:1)

如果你有一个指针向量,你可以这样做:

vector<Obstacle *> obsdata;

然后你“新”你的后续CIRCLE和RECTANGLE:

    if(shape=="CIRCLE") {
        CIRCLE *c = new CIRCLE;
        c->m_Xc=num1;
        c->m_Yc=num2;
        c->m_Radius=num3;       
        obsdata.push_back(c);
    }

等。

答案 2 :(得分:1)

您可以尝试一次只读取整行,然后将值标记化......

vector<Obstacle*> obsdata;

string line;
while(getline(fs, line)) {
    char *token = strtok(line.c_str(), " ");
    string shape(token);

    vector<double> numbers;
    stringstream ss;
    while(token = strtok(NULL, " ")) {
        double d;
        ss << token;
        ss >> d;

        numbers.push_back(d);
    }

    if(shape == "CIRCLE") {
        CIRCLE *c = new CIRCLE();
        c->m_Xc=numbers[0];
        c->m_Yc=numbers[1];
        c->m_Radius=numbers[2];       
        obsdata.push_back(c);
    } else if(shape == "RECTANGLE") {
        RECTANGLE *r = new RECTANGLE();
        r->center_x=numbers[0];
        r->center_y=numbers[1];    
        r->width=numbers[2];
        r->height=numbers[3];
        r->angle=numbers[4];
        obsdata.push_back(r);
    }
}

我会在你的MyWorld析构函数中删除这个指针向量:

~MyWorld() {
    // loop thanks to gf
    for(std::vector<Obstacle*>::iterator it = obsdata.begin(); it != obsdata.end(); ++it)
        delete *it;  
}

答案 3 :(得分:1)

这里的所有建议都很好,但我想提出两项改进建议:

  • 管理你的指针(我选择shared_ptr,但ptr_vector也会有效)
  • 使用对象工厂

这将使您的解决方案更加健壮(而不是泄漏内存)并且更具可扩展性(您可以删除随着障碍物数量增加而成为编译器瓶颈的“上帝”功能)。

您的代码可能类似于:

vector<shared_ptr<Obstacle> > obsdata; 

Myworld::readObstacles(std::istream &fs)
{
    std::string shape;
    while(fs >> shape)
    {
        try
        {
            obsdata.push_back(shared_ptr<Obstacle>(m_ObstacleCreator.Create(shape, fs));
        }
        catch(ObstacleNotKnownException& e)
        {
            // Error handling here
        }
    }
}

唯一剩下的就是填充m_ObstacleCreator,了解如何根据形状名称和istream创建各种对象。一个例子:

Obstacle * CreateCircleObstacle(istream &fs)
{
    CIRCLE *c = new CIRCLE();
    fs >> c->m_Xc >> c->m_Yc >> c->m_Radius;
}

m_ObstacleCreator.Register("CIRCLE", &CreateCircleObstacle);

您可能还想让m_ObstacleCreator成为单身人士(对象工厂是单身人士IMO为数不多的真正用途之一)。

有关Object Factory实现细节的精彩描述,请获取Alexandrescu的Modern C ++ Design的副本,并查看第8章。

答案 4 :(得分:0)

你的while循环的条件是个问题。 Circle比矩形少2个条目。我建议你阅读形状,然后根据类型读取剩下的数据。你知道你可以读取圆形的3个数据点和矩形的5个数据点。

一些伪代码

while( fs >> shape )
{
  if( shape == "CIRCLE" )
  { 
        CIRCLE c;
        fs >> c.m_Xc;
        fs >> c.m_Yc;
        fs >> c.m_Radius;       
        obsdata.push_back(c);
   }

  if( shape == "RECTANGLE" )
  {
      RECTANGLE r;
      fs >> r.center_x;
      fs >> r.center_y;    
      fs >> r.width;
      fs >> r.height;
      fs >> r.angle;
      obsdata.push_back(r);
  }
}

正如gf在评论中所建议的那样,有关标准库的优秀C ++书籍或教程会有所帮助。