【问题标题】:Dice Game c++ error undeclared identifier/code review骰子游戏 C++ 错误未声明的标识符/代码审查
【发布时间】:2017-02-06 20:25:35
【问题描述】:

我正在编写每个人都喜欢的 C++ 项目介绍。骰子游戏。我很难理解 C++ 如何来回发送信息以及如何在单独的文件中使用函数和类。我最大的问题是为什么我会在每个变量上都得到未声明的标识符?...

直方图.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];
        }
    }
}; 

直方图.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 个空格,因此格式可能有点偏差....

【问题讨论】:

  • 你得到的实际错误是什么?
  • “Pro”代码格式化提示:1)粘贴代码 2)选择代码 3)ctrl+k
  • 此代码无法编译。你确定你没有错过必要的图书馆吗?但是包括其他不需要的东西吗?
  • 您正在#include 来自另一个 .cpp 文件的 .cpp 文件——这通常是不对的,尽管您可以让它工作。目的是将每个 .cpp 文件编译为目标文件(.obj 或 .o 通常取决于您的编译器),然后链接在一起。
  • 您还包括来自标头的 .cpp,这更糟糕:(

标签: c++ arrays histogram dice undeclared-identifier


【解决方案1】:

首先,不要#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 在声明之前使用。
  • 在遇到#include &lt;iostream&gt; 之前使用std::cout
  • 在遇到#include &lt;iostream&gt; 之前使用std::endl
  • 如果编译器不按照您期望的方式尊重 #pragma once,则将重新定义 theHisto 类。

因此,您会收到“使用未定义的变量”错误。

相反,您希望编译器同时编译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 文件作为单独的翻译处理单元,而不是仅仅将它们组合成一个单独的大块。


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

【讨论】:

  • 另外,main() 应该返回int 而不是unsigned int,我建议将using namespace std 指令放在theHisto::printHisto()main() 中,而不是放在全局命名空间中。您也可以删除全局变量idie1die2,并用Dice::rollDie()中的局部变量替换它们。你没有使用output,所以你可以删除它。
  • 您还应该将您的标准库 #includes(&lt;cstdlib&gt;&lt;stdio.h&gt;&lt;iostream&gt;)移动到 main.cpphistogram.cpp,以便任何其他包含 @987654415 的文件@s histogram.h 也不会得到它们。我不确定你是否真的需要 &lt;stdio.h&gt;,就此而言;我没有看到任何使用它的东西。我还建议用srand() 播种rand();您可以在main() 的顶部执行此操作,也可以在Dice 的默认构造函数中执行此操作。 #include &lt;ctime&gt; 与您的其他库包括,并使用 srand(time(nullptr));
  • (如果您的编译器不符合 C++11,或者抱怨 nullptr,则使用编译器版本的开关 -std=c++11(如果可用;您也可以使用 @987654426 @),或将 nullptr 替换为 NULL。)
  • 我会尽快用更新的代码更新它。你们的帮助非常棒。我应该说一些事情,例如使用 histogram.cpp 而不是简化是任务的一部分,以便教我们 c++ 是如何工作的,即使我们知道它并不完全是一个理想的设置。
  • @BrenBailey 啊,好的。这是有道理的,知道如何将多个源文件编译到一个项目中是非常有用的,尤其是当您转向更复杂的项目时。很高兴我能帮上忙。
【解决方案2】:

以下是我在您的代码中看到的一些问题。我不知道这是否能解决您的问题,因为您没有发布错误消息。

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

【讨论】:

  • 我不同意 4。typedef 没有任何问题。
  • 所以这是我为每个变量得到的错误 Error C2065 'rolls': undeclared identifier histogram 你的意思是使用 stdio.h 而不是 cstdio 吗? main 应该返回 int 是什么意思?它应该返回什么int?
  • @BrenBailey main函数的返回类型具体是int,你用的是uint。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-19
  • 2017-07-11
  • 2012-02-29
  • 2020-05-11
  • 2015-08-25
  • 1970-01-01
  • 2013-12-03
相关资源
最近更新 更多