【问题标题】:A few questions regarding overloading stream operators in c++c++中关于重载流操作符的几个问题
【发布时间】:2012-04-11 17:27:25
【问题描述】:

我正在开发一个hangman 程序,我想在每次猜测后向用户输出一个状态报告。当我使用类时,我需要使用“朋友”关键字。我对班级和朋友的概念很满意,但是我正在努力在我的程序中正确实现它。

主要问题是没有计算元音的数量,并且用户可以尝试的字母数量没有更新。每次都会显示完整的字母表。

我的程序代码很丰富,我不打算在这里全部发布。我遇到的问题是函数remainingLetters();和vowelCount()。我附上了相关的代码sn-ps。这段代码显然不会编译。我只是希望有人能看到我遗漏的明显错误。

**Hangman.h:**
{
public:
...
int vowelCount()const; //to be implemented
char* remainingLetters()const;//to be implemented
friend ostream& operator<< (ostream &out, Hangman &game);

private:
...
int vowel_count;
char secretWord[MAXWORDLENGTH];
char* remaining_letters;
}

**hangman.cpp:**
{
...
int Hangman::vowelCount()const
{
  int vowel_count = 0;
  int i;
  secretWord[i];

  for(i=0; i<strlen(secretWord); i++)
  {


if(secretWord[i]=='a'||secretWord[i]=='e'||secretWord[i]=='i'||secretWord[i]=='o'||secretWord[i]=='u')
    {
      vowel_count++;
    }
  }
  return vowel_count;
}

char* Hangman::remainingLetters()const
{
  char alphabet[26]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
  char *remaining_letters=new char[ALPHABETSIZE];

  for(int i=0; i<strlen(secretWord); i++)
  {
  for(int j=0; j<ALPHABETSIZE; j++)
    {
       if(secretWord[i]!=alphabet[j])
       {
     remaining_letters[j]=alphabet[j];
       }
    }
  } 
 return remaining_letters;
}

ostream& operator<< (ostream &out, Hangman &game)
{
    out << "Number of guesses remaining is: " << game.numGuessesAllowed-game.numWrongGuesses << endl
     << "Number of incorrect guesses so far is: "<<game.numWrongGuesses <<endl
     << "Letters remaining are: "<<game.remaining_letters <<endl
     << "Hint: The secret word contains "<<game.vowel_count <<" vowels"<<endl;

    return out;
}
}

**main.cpp**
{
...
 cout << game;
...
return 0;
}

【问题讨论】:

  • 是的,这一行:secretWord[i]。 secterWord 到底应该是什么以及你在哪里初始化它?
  • 在我的代码中包含了 secretWord。它是一个 char 数组,由程序开始时的函数填充。
  • 每次调用remainingLetters()都会泄漏内存

标签: c++ class function operator-overloading


【解决方案1】:

您需要调用函数vowelCount()remainingLetters()来计算对应的变量(以便输出)。

另外,char *remaining_letters=new char[ALPHABETSIZE]; 将为字母分配内存并用 0 初始化每个位置——这也恰好是字符串的终止值。所以如果第一个位置(字母'a')没有设置,out&lt;&lt;game.remaining_letters不会输出任何东西

另外,函数vowelCount()定义了局部变量vowel_count,它隐藏了类中的那个(成员变量),所以成员变量不会被更新(除非你明确地将vowelCount()的返回值赋给那个成员变量)我建议你从vowelCount()函数中删除局部变量声明,它会使用你需要的成员变量

上一段也适用于成员变量remaining_letters

还有一点:new 分配的内存不会自动释放,一旦你从函数调用返回,分配的内存就会丢失(因为无法再次访问它,但它仍然使用内存),除非您在函数返回时分配它。您需要将每个 new[] 呼叫与其对应的 delete[] 呼叫相匹配。更好的是:在类的构造函数中分配内存并在成员变量的析构函数中删除它

注意:此逻辑中还有另一个错误:

for(int i=0; i<strlen(secretWord); i++) 
{ 
  for(int j=0; j<ALPHABETSIZE; j++) 
  { 
    if(secretWord[i]!=alphabet[j]) 
    { 
      remaining_letters[j]=alphabet[j]; 
    } 
  } 
}

您在字母表中循环,每次密码中的当前字母不匹配时,您分配给remaining_letters。每次都会发生这种分配,因为字母表中会有一个字母与当前的 secretWord 字母不匹配。

要解决此问题,您需要执行以下操作(注意循环的反转):

int secret_len = strlen(secretWord); // cache length, so we don't recalculate it
                                     // every time: secretWord does not change
for(int j=0; j<ALPHABETSIZE; j++) 
{ 
  bool found = false; // assume the current ABC letter is not in secretWord
  for(int i=0; i<secret_len; i++) 
  { 
    if(secretWord[i]!=alphabet[j]) 
    { 
      found = true; // but it was
    } 
  } 
  if (!found) // if it wasn't
  {
    remaining_letters[j]=alphabet[j]; 
  }
}

【讨论】:

  • 这很好,谢谢。只是一件事,我怎样才能防止第一个位置被设置为0?我应该将其定义为“a”吗?我不太确定你的意思是什么。另外,在 operator 函数中调用函数是否可行?而不是调用 main.cpp 中的函数?
  • 你当然可以在操作符主体中调用函数,但它可能会不必要地减慢它——通常保持函数/操作符主体尽可能精简是个好主意——在这种情况下,如果如果您想多次输出game 对象而不进行任何更改,则无需调用这些函数——尽管您当然可以进行一些缓存以避免重新计算,但不要忘记在某些情况下使缓存无效变化。关于字符串终止问题:您可以保留另一个特定于 remaining_letters 的计数器,并在 [cont] 时将其递增
  • [cont] 分配给remaining_letters 中的当前位置。这也带来了另一个错误:您的剩余字母计算不正确
  • 非常感谢 Attila。那里有一些非常有建设性的反馈。将相应地更新代码。
【解决方案2】:

您的主要问题是您没有在班级成员vowel_count 中保留元音计数。您将它存储在局部变量 vowel_count 中并返回它,但类成员永远不会更新。

【讨论】:

  • 我该怎么做?我认为一旦函数的原型中有类名,它就会返回相应的类成员?
  • 您在 vowelCount() 方法中声明 int vowel_count。你隐藏你的类成员,所以你返回的变量实际上是一个局部变量,在方法完成后它将无效。只需从方法中删除 int vowel_count 声明
  • 这样做并得到编译器错误:“只读对象中成员 'Hangman::vowel_count' 的增量”这是什么意思?
  • 您将该方法标记为 const,这意味着该方法不会更改对象的状态。在这种情况下,删除 const。
  • 表示既然vowelCount()被标记为const函数(见其签名),就不允许改变对象的状态(即:成员变量或调用其他非-const 函数)在该函数中 - 删除 const 它将起作用
猜你喜欢
  • 1970-01-01
  • 2021-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多