首先,不要#include "histogram.cpp",这是所有问题的根本原因。具体来说:
- 编译器将以
main.cpp 或histogram.cpp 开头,很可能是main.cpp。然后它将继续从每个 .cpp 文件创建单个翻译单元,方法是对其进行预处理并包含 #include 指令指定的每个文件。
- 在预处理
main.cpp时,会遇到#include "histogram.h"。这告诉预处理器将文件histogram.h 粘贴到main.cpp 的顶部,它遇到该行的位置。然后它将继续使用histogram.h 的内容进行预处理,直到它到达从文件粘贴的代码的末尾并移至main.cpp 中的下一行。
- 在预处理从
histogram.h 粘贴的代码时,会遇到#include "histogram.cpp"。这告诉预处理器将文件histogram.cpp 粘贴到那里,就像它对histogram.h 所做的那样。然后它将继续使用histogram.cpp 的内容进行预处理,直到它到达从文件粘贴的代码的末尾并移动到从histogram.h 粘贴的下一行。
-
#pragma once 将防止stdafx.h、histogram.h 和histogram.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 <iostream> 之前使用std::cout。
-
在遇到
#include <iostream> 之前使用std::endl。
- 如果编译器不按照您期望的方式尊重
#pragma once,则将重新定义 theHisto 类。
因此,您会收到“使用未定义的变量”错误。
相反,您希望编译器同时编译histogram.cpp 和main.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.cpp 和histogram.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。]