First, don't #include "histogram.cpp"
, that's the root cause of all the problems. Specifically:
- The compiler will start with either
main.cpp
or histogram.cpp
, most likely main.cpp
. It will then proceed to create a single translation unit from each .cpp
file, by preprocessing it and including every file specified by an #include
directive.
- While preprocessing
main.cpp
, it will encounter #include "histogram.h"
. This tells the preprocessor to paste the file histogram.h
at the top of main.cpp
, where it encounters that line. It will then continue preprocessing with the contents of histogram.h
, until it reaches the end of the code pasted from the file and moves on to the next line in main.cpp
.
- While preprocessing the code pasted in from
histogram.h
, it will encounter #include "histogram.cpp"
. This tells the preprocessor to paste the file histogram.cpp
there, just as it did for histogram.h
. It will then continue preprocessing with the contents of histogram.cpp
, until it reaches the end of the code pasted from the file and moves on to the next line pasted from histogram.h
.
#pragma once
will prevent stdafx.h
, histogram.h
and histogram.cpp
from being copy-pasted multiple times, and preprocessing will finish normally. [Note that #pragma once
may or may not guard against the #include "histogram.cpp"
in main.cpp
, since it's in histogram.h
and not main.cpp
. Similarly, if stdafx.h
contains anything, it may run into this same issue; I will assume that it's empty, and was automatically inserted by your IDE, and thus will only mention it once, at the top of the translation unit.] Compilation will now begin, with the following file:
// 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();
}
Note, if you will, that the body of histogram.cpp
is now placed before the body of histogram.h
, meaning:
frequency
is used before being declared.
rolls
is used before being declared.
std::cout
is used before #include <iostream>
is encountered.
std::endl
is used before #include <iostream>
is encountered.
- If the compiler doesn't respect
#pragma once
the way you expect it to, class theHisto
will be redefined.
Thus, you get "undefined variable used" errors.
Instead, you want your compiler to compile both histogram.cpp
and main.cpp
, and combine them during the linking phase. While we're at it, since you already #include "stdafx.h"
at the start of each .cpp
file, there's no need to do the same in histogram.h
.
Next, theHisto
should be defined in histogram.h
, not 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();
};
And...
// 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;
}
}
This will resolve the errors, but will cause linkage errors, due to your global variables being defined in multiple compilation units. To solve this, you can declare them as extern
in histogram.h
, and define them in one of the .cpp
files.
// 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();
};
And...
// 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;
}
}
And...
// 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();
}
This will solve the linkage errors, and allow your code to compile. Note that the compiler's command line should specify both main.cpp
and histogram.cpp
, and will likely look something like this (assuming Visual Studio, because of stdafx.h
).
cl /EHsc main.cpp histogram.cpp
Alternatively, you can eliminate histogram.cpp
entirely, by defining theHisto::printHisto()
as inline.
// 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;
}
}
};
And...
// 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();
}
This one will be compiled with the following, again assuming Visual Studio:
cl /EHsc main.cpp
Either of the previous two should fix your problem. I would recommend the former, so you can also move Dice::rollDie()
to histogram.cpp
, as I did with theHisto::printHisto()
. Just remember not to #include
any .cpp
files, unless 1) they're included after any code they depend on, and 2) you only #include
them in a single file, which should have a header guard. [Note that if you know what you're doing, and how to break the second rule safely, you can pull off a lot of crazy tricks.] It's generally better to tell the compiler to process each .cpp
file as a separate translation unit, instead of just combining them into a single, massive blob.
[See also the first comment on this answer, which contains further recommendations; they shouldn't be necessary to get your code to work, but will be useful. If anything, the one most likely to break is main()
's return type; while unsigned int
can be implicitly converted to int
, not every compiler will agree with main()
returning an unsigned int
instead of an int
.]