将istream传递给函数

时间:2013-01-27 15:37:41

标签: c++ ifstream istream

我正在制作类似于口袋妖怪概念的游戏类型程序。我们有一个锦标赛课程,跟踪几个团队(它自己的类),其中包括宠物(它自己的类),不同种类的宠物是CPet的子类。

我们正在尝试将文件名传递给main,从主传递该文件名到Tournament类。在Tournament类中,我们使用以下命令打开文件:

 14 //Construct a tournament
 15 CTournament::CTournament(const char *Filename){
 16         //opening file
 17         ifstream inFile(Filename, ios::in);
 18         if(inFile.bad()){
 19                 cout << "File error" << endl;
 20                 return ;
 21         }
 22          //get Teamlist for tournament
 23          while(!(inFile.eof())){
 24                  CTeam* temp = new CTeam;
 25                  temp->ParseTeam(inFile);
 26 
 27                  TeamList.push_back(temp);
 28          }
 29 }

这里我们将inFile传递给CTeam.ParseTeam,它看起来像:

     30 void CTeam::ParseTeam(std::istream in){
     31   string readline;
     32   getline(in, readline);
     33   this->TeamName = readline;
     34   while(!(in.eof())&&(readline != " " || readline != "/n"))
     35   {
     36           getline(in, readline);
     37           this->Parse(readline);
     38   }
     39 }

我们收到错误:

In file included from /usr/include/c++/4.4/ios:39,
                 from /usr/include/c++/4.4/ostream:40,
                 from /usr/include/c++/4.4/iostream:40,
                 from CTournament.h:11,
                 from CTournament.cpp:8:
/usr/include/c++/4.4/bits/ios_base.h: In copy constructor 'std::basic_ios<char, std::char_traits<char> >::basic_ios(const std::basic_ios<char, std::char_traits<char> >&)':
/usr/include/c++/4.4/bits/ios_base.h:790: error: 'std::ios_base::ios_base(const std::ios_base&)' is private
/usr/include/c++/4.4/iosfwd:47: error: within this context
/usr/include/c++/4.4/iosfwd: In copy constructor 'std::basic_istream<char, std::char_traits<char> >::basic_istream(const std::basic_istream<char, std::char_traits<char> >&)':
/usr/include/c++/4.4/iosfwd:53: note: synthesized method 'std::basic_ios<char, std::char_traits<char> >::basic_ios(const std::basic_ios<char, std::char_traits<char> >&)' first required here 
CTournament.cpp: In constructor 'CTournament::CTournament(const char*)':
CTournament.cpp:25: note: synthesized method 'std::basic_istream<char, std::char_traits<char> >::basic_istream(const std::basic_istream<char, std::char_traits<char> >&)' first required here 
CTournament.cpp:25: error:   initializing argument 1 of 'void CTeam::ParseTeam(std::istream)'

我知道有一个类似的问题,他不包括fstream。我们已将它包含在两个头文件中。

我想也许这是一个没有将正确的类型传递给PraseTeam的问题,但我找不到任何非常具体的关于如何将文件传递给ParseTeam以验证我是否正确执行此操作的问题。

提前致谢。

2 个答案:

答案 0 :(得分:13)

您需要通过引用传递流,因为流通常不可复制:

void CTeam::ParseTeam(std::istream &in)

答案 1 :(得分:1)

正如@dasblinkenlight已经指出的那样,你需要/想要通过引用传递流。

这只是冰山一角。您的代码有许多更有害的问题。其中最主要的是代码:

while(!(inFile.eof()))

这样的代码被打破了。它不会起作用。它从来没有,它永远不会(缺少一些重大奇迹发生)。几乎不可能在循环中放入一个条件(带有break语句)以在正确的时间退出循环 - 但是你还没有这样做,而且几乎没有其他人也这样做了,当你这样做时,你可能会同样将循环本身转换为while (true),因为它始终是其他逻辑在正确的时间退出循环 - 因为这个循环条件不能也不会。 [我并不是说在那里听起来很苛刻或讨厌,只是试图完全清楚这段代码绝对工作。]

您在此处再次遇到相同的基本问题:

 while(!(in.eof())&&(readline != " " || readline != "/n"))

这增加了我猜的另一个问题(虽然不太常见,也更容易解决)问题 - 您的"/n"几乎肯定是"\n"

在大多数情况下,您真正​​想要/需要做的是从流中读取内容,并使读取的函数返回对流的引用。这将让您读取项目,直到读取失败(此时应设置流的failbit)。完成后,您可以使循环以读取成功为条件。在大多数的情况下,将函数命名为operator>>很方便,因此读取类的对象使用的语法与读取像int这样的内容相同。

例如,让我们来看看您的parseTeam

 void CTeam::ParseTeam(std::istream in){
   string readline;
   getline(in, readline);
   this->TeamName = readline;
   while(!(in.eof())&&(readline != " " || readline != "/n"))
   {
           getline(in, readline);
           this->Parse(readline);
   }
 }

如果由我决定,我会写更多这样的东西:

std::istream &operator>>(std::istream &is, CTeam &t) { 
     std::getline(is, t.Teamname);
     CTeam::member member;
     while (is >> member)
         t.members.push_back(member);
     return is;
}

然后,CTeam将沿着这条总路线:

class CTeam {
    // ...
public:
    class member { 
        // ...     
        friend std::istream &operator>>(std::istream &is, member &m) { 
            // code to read one team member from is
        }
    };
};

我还应该补充一点,在不了解该计划的情况下,该组织肯定是具体 - 例如,我不清楚我所显示的实体{{1}实际上可能存在于团队的上下文之外。如果可以,那么你(几乎可以肯定)想要在CTeam之外使它成为一个独立的类。目前,我只是在猜测如何根据我发布的代码收集代码来组织代码。

摘要:CTeam::member形式的任何内容都无法挽回。你几乎总是想要while (!whatever.eof())。 C ++中的约定是使用while (read_something())从流中读取项目。如果可能的话,遵循该惯例。哦,是的,你几乎总是希望通过引用传递流(异常是你需要使用指向流的指针的奇怪时间 - 异常,但它确实会一次又一次地发生)。