骰子游戏c++错误未声明的标识符/代码审查

Dice Game c++ error undeclared identifier/code review

本文关键字:标识符 代码审查 未声明 错误 游戏 c++      更新时间:2023-10-16

我正在做大家最喜欢的c++入门项目。骰子游戏。我真的很难理解c++是如何来回发送信息的,以及如何在单独的文件中使用函数和类。我最大的问题是为什么我在每个变量上得到未声明的标识符?…

histogram.h

#pragma once
#include "stdafx.h"
#include "histogram.cpp"
#include <cstdlib>
#include <stdio.h>
#include <iostream>
typedef unsigned int uint;
uint rolls = 0, i = 0, die1 = 0, die2 = 0, output = 0, show = 0;
uint frequency[12] = { 0 };
class Dice
{
public:
    void inline rollDie(uint rolls)
    {
        for (i = 1; i <= rolls; i++) {
            die1 = 1 + rand() % 6;
            die2 = 1 + rand() % 6;
            ++frequency[die1 + die2];
        }
    }
}; 

histogram.cpp

#include "stdafx.h"
#include "histogram.h"
using namespace std;
class theHisto 
{
public:
    void printHisto()
    {
        for (int i = 1; i < 12; i++)
        {
            //Output some asterisks for the histogram
            for (int freq = (frequency[i] * 100 / rolls); freq > 0; freq--)
                cout << "*";
            cout << endl;
        }
    }
};

main.cpp

#include "stdafx.h"
#include "histogram.h"
#include "histogram.cpp"
using namespace std;
uint main()
{
    cout << "How many times would you like to roll the dice?";
    cin >> rolls;
    Dice myDice;
    myDice.rollDie(rolls);
    theHisto mytheHisto;
    mytheHisto.printHisto();
}

对不起,如果这是混乱的,但当我复制代码到"输入代码在这里"框,它只是显示为常规文本,所以我不得不缩进每一行4个空格,所以格式可能有点off....

首先,不要#include "histogram.cpp",这是所有问题的根源。具体来说:

  1. 编译器将从main.cpphistogram.cpp开始,最有可能是main.cpp。然后,它将继续从每个.cpp文件创建一个单一的翻译单元,通过预处理它并包括#include指令指定的每个文件。
  2. 预处理main.cpp时,会遇到#include "histogram.h"。这告诉预处理器将文件histogram.h粘贴到main.cpp的顶部,也就是它遇到这一行的地方。然后,它将继续对histogram.h的内容进行预处理,直到到达从文件粘贴的代码的末尾,并移动到main.cpp中的下一行。
  3. 在预处理从histogram.h粘贴进来的代码时,会遇到#include "histogram.cpp"。这告诉预处理器将文件histogram.cpp粘贴到那里,就像它对histogram.h所做的那样。然后,它将继续对histogram.cpp的内容进行预处理,直到它到达从文件粘贴的代码的末尾,并继续移动到从histogram.h粘贴的下一行。
  4. #pragma once将阻止stdafx.hhistogram.hhistogram.cpp被多次复制粘贴,预处理将正常完成。[注意,#pragma once可能会也可能不会防止main.cpp中的#include "histogram.cpp",因为它在histogram.h中而不是main.cpp中。]同样,如果stdafx.h包含任何内容,它可能会遇到同样的问题;我假设它是空的,并且是由您的IDE自动插入的,因此只会在翻译单元的顶部提到它一次。编译现在将开始,使用以下文件:

    // Contents of "stdafx.h" here.
    using namespace std;
    
    class theHisto {
    public:
        void printHisto()
        {
            for (int i = 1; i < 12; i++)
            {
                //Output some asterisks for the histogram
                for (int freq = (frequency[i] * 100 / rolls); freq > 0; freq--)
                    cout << "*";
                cout << endl;
            }
        }
    };
    // Contents of <cstdlib> here.
    // Contents of <stdio.h> here.
    // Contents of <iostream> here.
    
    typedef unsigned int uint;
    uint rolls = 0, i = 0, die1 = 0, die2 = 0, output = 0, show = 0;
    uint frequency[12] = { 0 };
    class Dice
    {
    
    public:
    
        void inline rollDie(uint rolls)
        {
            for (i = 1; i <= rolls; i++) {
                die1 = 1 + rand() % 6;
                die2 = 1 + rand() % 6;
                ++frequency[die1 + die2];
            }
        }
    };
    // Contents of "histogram.cpp" may also be here.
    using namespace std;
    
    uint main()
    {
        cout << "How many times would you like to roll the dice?";
        cin >> rolls;
        Dice myDice;
        myDice.rollDie(rolls);
        theHisto mytheHisto;
        mytheHisto.printHisto();
    }
    

请注意,histogram.cpp的主体现在被放在histogram.h的主体之前,意思是:

  • frequency在声明前使用。
  • rolls在声明之前使用。
  • std::cout在遇到#include <iostream>之前使用。
  • std::endl#include <iostream>之前使用。
  • 如果编译器不尊重#pragma once,类theHisto将被重新定义。

因此,您会得到"undefined variable used"错误。

相反,您希望编译器同时编译histogram.cppmain.cpp,并在链接阶段将它们组合起来。既然我们已经在每个.cpp文件的开头添加了#include "stdafx.h",那么就不需要在histogram.h中做同样的事情了。


接下来,theHisto应该在histogram.h中定义,而不是histogram.cpp

// histogram.h
#pragma once
// #include "stdafx.h"
// #include "histogram.cpp"
#include <cstdlib>
#include <stdio.h>
#include <iostream>
typedef unsigned int uint;
uint rolls = 0, i = 0, die1 = 0, die2 = 0, output = 0, show = 0;
uint frequency[12] = { 0 };
class Dice
{
public:
    void inline rollDie(uint rolls)
    {
        for (i = 1; i <= rolls; i++) {
            die1 = 1 + rand() % 6;
            die2 = 1 + rand() % 6;
            ++frequency[die1 + die2];
        }
    }
};
class theHisto
{
public:
    void printHisto();
};

// histogram.cpp
#include "stdafx.h"
#include "histogram.h"
using namespace std;
void theHisto::printHisto()
{
    for (int i = 1; i < 12; i++)
    {
        //Output some asterisks for the histogram
        for (int freq = (frequency[i] * 100 / rolls); freq > 0; freq--)
            cout << "*";
        cout << endl;
    }
}

这将解决错误,但会导致链接错误,因为您的全局变量是在多个编译单元中定义的。为了解决这个问题,您可以在histogram.h中将它们声明为extern,并在.cpp文件之一中定义它们。

// histogram.h
#pragma once
// #include "stdafx.h"
// #include "histogram.cpp"
#include <cstdlib>
#include <stdio.h>
#include <iostream>

typedef unsigned int uint;
extern uint rolls, i, die1, die2, output, show;
extern uint frequency[12];
class Dice
{
public:
    void inline rollDie(uint rolls)
    {
        for (i = 1; i <= rolls; i++) {
            die1 = 1 + rand() % 6;
            die2 = 1 + rand() % 6;
            ++frequency[die1 + die2];
        }
    }
};
class theHisto
{
public:
    void printHisto();
};

// histogram.cpp
#include "stdafx.h"
#include "histogram.h"
using namespace std;

uint rolls = 0, i = 0, die1 = 0, die2 = 0, output = 0, show = 0;
uint frequency[12] = { 0 };

void theHisto::printHisto()
{
    for (int i = 1; i < 12; i++)
    {
        //Output some asterisks for the histogram
        for (int freq = (frequency[i] * 100 / rolls); freq > 0; freq--)
            cout << "*";
        cout << endl;
    }
}

// main.cpp
#include "stdafx.h"
#include "histogram.h"
// #include "histogram.cpp"
using namespace std;
// You could define your variables here, instead of in "histogram.cpp", if you wanted.
uint main()
{
    cout << "How many times would you like to roll the dice?";
    cin >> rolls;
    Dice myDice;
    myDice.rollDie(rolls);
    theHisto mytheHisto;
    mytheHisto.printHisto();
}

这将解决链接错误,并允许您的代码编译。注意,编译器的命令行应该同时指定main.cpphistogram.cpp,并且可能看起来像这样(假设是Visual Studio,因为stdafx.h)。

cl /EHsc main.cpp histogram.cpp

或者,您可以通过将theHisto::printHisto()定义为内联来完全消除histogram.cpp

// histogram.h
#pragma once
// #include "stdafx.h"
// #include "histogram.cpp"
#include <cstdlib>
#include <stdio.h>
#include <iostream>

typedef unsigned int uint;
extern uint rolls, i, die1, die2, output, show;
extern uint frequency[12];
class Dice
{
public:
    void inline rollDie(uint rolls)
    {
        for (i = 1; i <= rolls; i++) {
            die1 = 1 + rand() % 6;
            die2 = 1 + rand() % 6;
            ++frequency[die1 + die2];
        }
    }
};
using namespace std;
class theHisto
{
public:
    void printHisto()
    {
        for (int i = 1; i < 12; i++)
        {
            //Output some asterisks for the histogram
            for (int freq = (frequency[i] * 100 / rolls); freq > 0; freq--)
                cout << "*";
            cout << endl;
        }
    }
};

// main.cpp
#include "stdafx.h"
#include "histogram.h"
// #include "histogram.cpp"
using namespace std;

uint main()
{
    cout << "How many times would you like to roll the dice?";
    cin >> rolls;
    Dice myDice;
    myDice.rollDie(rolls);
    theHisto mytheHisto;
    mytheHisto.printHisto();
}

这个将用下面的代码编译,再次假设Visual Studio:

cl /EHsc main.cpp

前面两个中的任何一个都应该解决您的问题。我建议使用前者,因此您也可以将Dice::rollDie()移动到histogram.cpp,就像我对theHisto::printHisto()所做的那样。只要记住不要#include任何.cpp文件,除非1)它们包含在任何它们所依赖的代码之后的,以及2)您只在单个文件中#include它们,该文件应该有一个头保护。请注意,如果你知道你在做什么,以及如何安全地打破第二条规则,你可以完成很多疯狂的把戏。一般来说,最好告诉编译器将每个.cpp文件作为一个单独的翻译单元来处理,而不是将它们组合成一个单独的、大量的blob。


[参见对这个答案的第一条评论,其中包含进一步的建议;它们不应该是让你的代码工作所必需的,但是会很有用。如果有的话,最有可能打破的是main()的返回类型;虽然unsigned int可以隐式地转换为int,但并不是每个编译器都同意main()返回unsigned int而不是int

我看到你的代码有一些问题。我不知道这是否解决了你的问题,因为你没有发布错误信息。

  1. 方法main()应该返回int
  2. frequency数组太小。或者die1die2的值太大。这要看你怎么看了
  3. 你正在混合c++和C头文件。包含cstdio而不是stdio.h。最好不要使用cstdiocstdlib。你不需要他们。
  4. 使用unsigned作为数据类型,而不是你自己定义的uint
  5. 你没有初始化你的随机数生成器