Reputation: 548
I'm having some trouble thinking of how to structure a program in C++. I am following a book in learning C++ and at one point we construct two classes in an effort to solve a problem. The book ends up putting both classes, and how they're used all in one file and running it, and this works. But I understand more properly structured code would include header files and each class would get it's own file, and trying to structure the program like this is causing problems when I try to get the code to compile.
I have two classes, Token and Token_Stream, from other languages I know Token and Token_Stream should get their own files and that each should have a declaration file. My main issue is:
Token_Stream needs to know about Token. When a Token_Stream is initialized it initializes a Token. I had thought it would suffice to have just the declaration of Token included in Token_Stream and that would be enough, but that appears not to be the case. I know a bit about programming with OOP languages, but Token_Stream does not inherit anything from Token, nor should it (I believe) it just needs to know enough to initialize a Token and store it. I will include each of the relevant files below:
Token.h
// Token.h, declaration for Token
class Token
{
public:
char kind;
double value;
Token(char ch);
Token(char ch, double val);
}; //class Token
Token.cpp
// Token.cpp
#include "Token.h"
using namespace std;
Token::Token(char ch)
:kind(ch), value(0){}
Token::Token(char ch, double val)
:kind(ch), value(val) {}
Token_Stream.h
// Token_Stream.h, declarations
class Token_Stream
{
public:
Token_Stream();
Token get();
void putback(Token);
private:
bool full; // do we already hold a token?
Token buffer; // what Token do we hold?
};//class Token_Stream
Token_Stream.cpp
// Token_Stream.cpp implementation.
#include <iostream>
#include <stdexcept>
#include "Token.h" // needs to know what a Token is
#include "Token_Stream.h"
using namespace std;
/***********************************************************************
* Token_Stream::Token_Stream()
*
* Constructor for Token_Stream(), sets full = false and buffer as 0
* Need to do :buffer(0), so we don't create an extra buffer variable
**********************************************************************/
Token_Stream::Token_Stream()
:buffer(0)
{
full = false; // nothing in our stream yet.
}//constructor
/***********************************************************************
* void Token_Stream::put_back(Token t)
*
* Given a token, we fill buffer and change full to true
*
* Parameter: t - Token to fill buffer
**********************************************************************/
void Token_Stream::putback(Token t)
{
if(!full) // if its empty
{
buffer = t;
full = true;
}//if not full
else
throw runtime_error("buffer already full");
}// putback
/***********************************************************************
* Token Token_Stream::get()
*
* gets another token from input, or if we have one stored, gets that.
*
* Returns: Token - next token in stream, either from buffer or from
* input
**********************************************************************/
Token Token_Stream::get()
{
if(full) //if we already have something
{
full = false;
return buffer;
}
//if we've reached here we haven't returned:
char ch;
cin>>ch; //get next input and switch over cases:
switch(ch)
{
// if they input a valid character:
case ';':
case 'q':
case '(': case '+': case '*': case '-': case '/': case '%':
case ')':
return Token(ch);
break;
//if they input a valid number, or lead with a decimal i.e., .5
case '.': case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
cin.putback(ch);
double val;
cin>>val; //read it as a number
return Token('8',val);
break;
}//case of valid number
default:
throw runtime_error("Bad Token");
}//switch
}//get
So those are the files, and when I try to compile things, i.e., put a blank int main(){} in Token.cpp, everything works fine, I compile, and if I wanted to I could run things in main()
But when I try put a blank int main(){} in Token_Stream.cpp and try to compile it does not work, I am running:
g++ -Wall -std=c++11 -o "Token_Stream" "Token_Stream.cpp"
and I am not even getting line number errors, but its claiming an undefined reference to Token::Token(char) etc and the rest of the Token constructors, so I'm guessing that this means that Token_Stream.cpp needs to see more of Token.cpp, how do I do this? Do I just simultaneously compile them?
Upvotes: 0
Views: 332
Reputation: 947
You need to link Token.cpp to your executable.
g++ -Wall -std=c++11 -o "Token_Stream" "Token.cpp" "Token_Stream.cpp"
Otherwise gcc won't find the implementation of Token's constructor.
Upvotes: 2
Reputation: 39354
Besides your linking problems, if you are looking for proper structures within programs you still need to sort out your dependencies.
Token_Stream.h should start like this:
// Token_Stream.h, declarations
#include "Token.h" // Note that this include is at the top.
class Token_Stream
...
Token_Stream.cpp should start like this:
// Token_Stream.cpp implementation.
#include "Token_Stream.h" // Note that this include is at the top.
#include <iostream>
#include <stdexcept>
...
The main points above are:
These prerequisites will allow your clients to include your headers wherever they need them.
Upvotes: 0