I've got the following functions declared in creature.h (under public):
void _hop();
void _turn(size_t way);
void _infect();
Point _facing();
bool _isEmpty();
bool _wall();
bool _same();
Then their implementation in the .cc (I've deleted a bunch of code for shortness):
void Creature::_hop(){
CODE
}
Point Creature::_facing(){
CODE
}
void Creature::_infect(){
CODE
}
bool Creature::_isEmpty(){
CODE
}
bool Creature::_wall(){
CODE
}
bool Creature::_same(){
CODE
}
But then upon compile I get these errors:
creature.cc:25: error: no 'void Creature::_hop()' member function declared in class 'Creature'
creature.cc:54: error: no 'void Creature::_turn(size_t)' member function declared in class 'Creature'
creature.cc:88: error: no 'geometry::Point Creature::_facing()' member function declared in class 'Creature'
creature.cc:105: error: no 'void Creature::_infect()' member function declared in class 'Creature'
creature.cc:114: error: no 'bool Creature::_isEmpty()' member function declared in class 'Creature'
creature.cc:121: error: no 'bool Creature::_wall()' member function declared in class 'Creature'
creature.cc:127: error: no 'bool Creature::_same()' member function declared in class 'Creature'
tons of other functions are getting read fine but these ones aren't getting any love. ?????
EDIT:
Not sure about the down votes, probably because you guys are assuming that I didn't either a) include it in the creature class or b) #include "creature.h". I did both, just didn't include that in the question since I thought that was obvious.
EDIT 2: You want .cc and .h? Oh dear lord.
CREATURE.H:
#ifndef CREATURE
#define CREATURE
class Creature {
public:
// Constructor (note there is no need for a destructor.)
Creature();
Creature(Species *species,World *world,Point pt,Direction d);
// takeOneTurn executes lines of this creature's species program,
// beginning on programLine and continuing until a HOP, LEFT, RIGHT, or
// INFECT is executed.
void takeOneTurn();
// getters and setters do the obvious things.
Species *getSpecies();
Direction getDirection();
// use this to initialize and infect. It also sets programLine to 1.
void setSpecies(Species * s);
void _hop();
void _turn(size_t way);
void _infect();
Point _facing();
bool _isEmpty();
bool _wall();
bool _same();
private:
Species *species; // pointer to this creature's species
World *world; // a pointer to the world in which this
// creature is located.
Point loc; // where in the world this creature is located
Direction dir; // current direction this creature is facing
size_t programLine; // current program line
};
#endif
CREATURE.CC
#include "creature.h"
#include <cstdlib>
Creature::Creature(Species *s, World *w,Point pt,Direction d){
world = w;
species = s;
loc = pt;
dir = d;
programLine = 0;
}
Species* Creature::getSpecies(){
return species;
}
Direction Creature::getDirection(){
return dir;
}
void Creature::setSpecies(Species* s){
species = s;
}
void Creature::_hop(){
switch(dir){
case NORTH:
if(!world->getContents(Point(loc.col,loc.row+1))){
world->setContents(loc, NULL);
world->setContents(Point(loc.col,loc.row+1), this);
}
break;
case SOUTH:
if(!world->getContents(Point(loc.col,loc.row-1))){
world->setContents(loc, NULL);
world->setContents(Point(loc.col,loc.row-1), this);
}
break;
case EAST:
if(!world->getContents(Point(loc.col+1,loc.row))){
world->setContents(loc, NULL);
world->setContents(Point(loc.col+1,loc.row), this);
}
break;
case WEST:
if(!world->getContents(Point(loc.col-1,loc.row))){
world->setContents(loc, NULL);
world->setContents(Point(loc.col-1,loc.row), this);
}
break;
}
}
void Creature::_turn(size_t way){
if(way == 0){
switch(dir){
case NORTH:
dir = WEST;
return;
case WEST:
dir = SOUTH;
return;
case SOUTH:
dir = EAST;
return;
case EAST:
dir = NORTH;
return;
}
} else {
switch(dir){
case NORTH:
dir = EAST;
return;
case WEST:
dir = NORTH;
return;
case SOUTH:
dir = WEST;
return;
case EAST:
dir = SOUTH;
return;
}
}
}
Point Creature::_facing(){
switch(dir){
case NORTH:
return Point(loc.col,loc.row+1);
break;
case WEST:
return Point(loc.col-1,loc.row);
break;
case SOUTH:
return Point(loc.col,loc.row-1);
break;
case EAST:
return Point(loc.col+1,loc.row);
break;
}
}
void Creature::_infect(){
Point facing = _facing();
if(!world->inRange(facing))return;
Creature* enemy = world->getContents(facing);
if(!enemy) return;
enemy->setSpecies(species);
world->setContents(facing, enemy);
}
bool Creature::_isEmpty(){
Point facing = _facing();
if(!world->inRange(facing))return false;
if(!world->getContents(facing)) return true;
return false;
}
bool Creature::_wall(){
Point facing = _facing();
if(!world->inRange(facing))return true;
return false;
}
bool Creature::_same(){
Point facing = _facing();
if(!world->inRange(facing))return true;
if(!world->getContents(facing)) return false;
Creature* enemy = world->getContents(facing);
return (enemy->species == species);
}
bool _random(){
int k = random();
return (k%2);
}
void Creature::takeOneTurn(){
Instruction whatToDo = species->programStep(programLine);
switch(whatToDo.op){
case HOP:
_hop();
programLine++;
break;
case LEFT:
_turn(0);
programLine++;
break;
case RIGHT:
_turn(1);
programLine++;
break;
case INFECT:
_infect();
programLine++;
break;
case IFEMPTY:
if(_isEmpty()){
programLine = whatToDo.line;
takeOneTurn();
}
break;
case IFWALL:
if(_wall()){
programLine = whatToDo.line;
takeOneTurn();
}
break;
case IFSAME:
if(_same()){
programLine = whatToDo.line;
takeOneTurn();
}
break;
case GO:
programLine = whatToDo.line;
takeOneTurn();
break;
case IFRANDOM:
if(_random()) programLine = whatToDo.line;
else programLine++;
takeOneTurn();
break;
}
}
Phew!
What you have described should work fine, so we have to assume that your description doesn't quite match reality.
Specifically, the following code compiles and runs fine.
pax$ cat creature.h
class Creature {
public:
void _hop();
};
pax$ cat creature.cc
#include <iostream>
#include "creature.h"
void Creature::_hop() {
std::cout << "Hop\n";
}
int main (void) {
Creature c;
c._hop();
return 0;
}
pax$ rm creature ; g++ -o creature creature.cc ; ./creature
Hop
Since that transcript shows what you seem to be doing, my advice is to post your actual code for analysis, including the full header file and almost full source file (you can leave in the CODE markers since they won't affect this particular problem but it would be useful to see things like the include statements and so forth).
The best problem reports should come with:
the expected behaviour.
the actual behaviour.
a small complete program that exhibits the errant behaviour.
Based on your code updates (and assuming they're complete), you have the problem that size_t, Species, World, Point and Direction are not actually defined before you include creature.h in your creature.cc file.
This is causing the creation of the Creature class to fail on the second constructor so that it doesn't know about that class. Then, when you try to define the actual code for said class, the compiler (rightly) complains that it doesn't exist.
When I add a very small main to your code and try to compile, I get these header file problems:
In file included from creature.cc:1:
creature.h:5: error: expected `)' before '*' token
creature.h:13: error: ISO C++ forbids declaration of 'Species' with no type
creature.h:13: error: expected ';' before '*' token
creature.h:14: error: 'Direction' does not name a type
creature.h:16: error: 'Species' has not been declared
creature.h:18: error: 'size_t' has not been declared
creature.h:20: error: 'Point' does not name a type
creature.h:26: error: ISO C++ forbids declaration of 'Species' with no type
creature.h:26: error: expected ';' before '*' token
creature.h:27: error: ISO C++ forbids declaration of 'World' with no type
creature.h:27: error: expected ';' before '*' token
creature.h:29: error: 'Point' does not name a type
creature.h:30: error: 'Direction' does not name a type
creature.h:31: error: 'size_t' does not name a type
which are caused by those non-definitions.
Then I see the sort of errors you describe, such as:
creature.cc:129: error: 'world' was not declared in this scope
creature.cc:129: error: 'facing' was not declared in this scope
creature.cc:130: error: 'world' was not declared in this scope
creature.cc:130: error: 'facing' was not declared in this scope
creature.cc:131: error: 'world' was not declared in this scope
creature.cc:131: error: 'facing' was not declared in this scope
creature.cc:132: error: 'class Creature' has no member named 'species'
creature.cc:132: error: 'species' was not declared in this scope
(just a sample of the many pages of output).
You need to ensure that you have included the header files which define those types before including creature.h. Ideally, creature.h would do this itself rather than relying on whatever is using it to do it.
size_t can be found in <cstring>, the others need to be found by yourself. For example, placing:
#include <cstring>
typedef int Species;
typedef int World;
typedef int Point;
typedef int Direction;
at the top of your header file gets rid of all those errors - it introduces a bucketload of other errors since the typedef statements are wrong but I'm just illustrating what you need to do here.
Find out where those other things are defined and include them, along with <cstring>, at the top of creature.h.
It looks like you're trying to write a class. You have to put the function declarations in a class declaration, then include the header in the source file.
Creature.h
class Creature {
private: // assuming these are private functions
void _hop();
void _turn(size_t way);
void _infect();
Point _facing();
bool _isEmpty();
bool _wall();
bool _same();
}; // don't forget the ;
Creature.cc
#include "Creature.h"
... your original Creature.cc contents ...
If you're not writing a class but a series of free functions, remove the Creature:: from your function names in Creature.cc.
Your header file says that the functions are standalone, but your source file says they belong to the "Creature" class. At the very minimum, you need to either:
surround your declarations with a struct or class
struct Creature
{
....your function declarations...
};
or
Remove the Creature:: from your cpp file.
Finally, starting function names with an undescore is bad practice. Don't do it.
Just before
class Creature {
try adding the following:
#error The class declaration for Creature is indeed being compiled
And see if that generates an error. If not, then I suspect something went wrong with your header guard.
Your header guard macro name should be longer than just CREATURE. It's too easy for a CREATURE macro to be accidentally defined somewhere else (like in a library) and messing up your header guard. If the name of your project is, say, "Monster Mash", then your header guard for creature.h should be something complicated like: MONSTER_MASH_CREATURE_H or MONSTER_MASH_CREATURE_INCLUDE. That way, it's extremely improbable that someone else has already defined your header guard macro.
Move #include "creature.h" to the TOP of the list of includes in your creature.cc file. Then, fix the compile errors (types 'Point', etc. not defined), and try again. The creature.h file needs to include or forward-declare all the types it uses, or you get weird problems.
I also second the suggestion to put a #error just above the Creature class declaration, to ensure that CREATURE didn't somehow get defined elsewhere (and thus force the class declaration to be skipped). And you might want a more unique header on your header file -- my own convention would have been _CREATURE_H_
Anyway, the upshot is that most of these kinds of bugs are caused by problems somewhere else, and the symptoms are only distantly related to the reason. C++, alas, is loaded with these kinds of gotchas.
Related
Had some issues in my code recently surrounding what I now know of as a Circular dependency. In short there are two classes, Player and Ball, which both need to use information from the other. Both at some point in the code will be passed a reference of the other (from another class that will include both .h files).
After reading up on it, I removed the #include.h files from each one and went with forward declaration. This solved the issue of being able to declare the classes in eachother, but I'm now left with an "Incomplete type error" when trying to access a passed reference to the object. There seem to be a few similar examples around, though often mixed with more complex code and hard to narrow down to the basics.
I've rewritten the code in it's simplest form (a skeleton essentially).
Ball.h:
class Player;
class Ball {
public:
Player& PlayerB;
float ballPosX = 800;
private:
};
Player.h:
class Ball;
class Player {
public:
void doSomething(Ball& ball);
private:
};
Player.cpp:
#include "Player.h"
void Player::doSomething(Ball& ball) {
ball.ballPosX += 10; // incomplete type error occurs here.
}
Any help understanding why this is the case would be greatly appreciated :)
If you will place your definitions in this order then the code will be compiled
class Ball;
class Player {
public:
void doSomething(Ball& ball);
private:
};
class Ball {
public:
Player& PlayerB;
float ballPosX = 800;
private:
};
void Player::doSomething(Ball& ball) {
ball.ballPosX += 10; // incomplete type error occurs here.
}
int main()
{
}
The definition of function doSomething requires the complete definition of class Ball because it access its data member.
In your code example module Player.cpp has no access to the definition of class Ball so the compiler issues an error.
Player.cpp require the definition of Ball class. So simply add #include "Ball.h"
Player.cpp:
#include "Player.h"
#include "Ball.h"
void Player::doSomething(Ball& ball) {
ball.ballPosX += 10; // incomplete type error occurs here.
}
Here is what I had and what caused my "incomplete type error":
#include "X.h" // another already declared class
class Big {...} // full declaration of class A
class Small : Big {
Small() {}
Small(X); // line 6
}
//.... all other stuff
What I did in the file "Big.cpp", where I declared the A2's constructor with X as a parameter is..
Big.cpp
Small::Big(X my_x) { // line 9 <--- LOOK at this !
}
I wrote "Small::Big" instead of "Small::Small", what a dumb mistake..
I received the error "incomplete type is now allowed" for the class X all the time (in lines 6 and 9), which made a total confusion..
Anyways, that is where a mistake can happen, and the main reason is that I was tired when I wrote it and I needed 2 hours of exploring and rewriting the code to reveal it.
In my case it was because a typo.
I had something like
struct SomethingStrcut { /* stuff */ };
typedef struct SomethingStruct smth;
Notice how the name of the structure is not the same one as the type definition.
I misspelled struct to strcut.
Look into your code and see wether you have some typos.
I'm having trouble implementing a state machine for class. I keep getting the errors:
state.cpp:5: error: have0 was not declared in this scope
state.cpp:10: error: redefinition of State* Have0State::process(std::string)
state.h:18: error: virtual State* Have0State::process(std::string) previously defined here
I'm trying to get the Have0State to work before I continue onto the rest of the machine, hence the sparse code.
state.h:
#ifndef STATE_H
#define STATE_H
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <iostream>
class State{
public:
State(){};
virtual State* process(std::string input) = 0;
};
class Have0State: public State {
public:
Have0State():State(){};
virtual State* process(std::string input);
}have0;
#endif
state.cpp:
#include "state.h"
using namespace std;
State *currentState = &have0;
State* Have0State::process(string input){
if(input == "quarter"){
cout << "cool" << endl;
}
return &have0;
}
int main(int argc, char** argv) {
string input;
//get input
cin >> input;
while (input != "exit") {
currentState = currentState->process(input);
//get input
cin >> input;
}
return 0;
};
I've tried defining the process function as Have0State::State::process(string input) but that didn't work either. Any clarification on how function pointers are supposed to work, especially in the context of subclass member functions, I would greatly appreciate it.
EDIT: Also, what exactly is the have0 declaration at the end of the Have0State class declaration in the state.h file? It doesn't have an explicitly stated type; is it implied that it is of type Have0State??
There aren't any function pointers in your example. Also, like Marciej, I am able to compile (and run) this code.
But, since you asked, the 'have0' declaration simply declares an instance of the class. A class definition can be followed by 0 or more of these declarations (as well as initializers):
class Thing {...} one, another, many[3] = { Thing(1), Thing(2), Thing(3) };
the same as for any other type:
int counter = 0, flag = 0x80, limit = 500;
The possibility of this optional declarator list is why class, struct, union, and enum definitions must be followed with a semi-colon (to terminate the list).
But, as Karthik said, defining a variable in a header will cause "duplicate definition" errors at link time, if the header is included in more than one .cpp file. IMO it's fine though to use this technique to define and declare private objects in a .cpp file (rather than a .h file).
Im spending my saturday night not dressed up for halloween but rather sitting trying to learn CPP :D
anyways could someone please help me, Below I have included my source code, basically when I try compiling this form the terminal I'm getting a lot of errors, basically stating that the variables "name, ho, etc" are not declared, yet I have included my header file, so could someone pleas shave a look at this and maybe tell me what is missing? Thank you so much in advance guys!
#ifndef __TPLAYER__
#define __TPLAYER__ //prevent multiple #includes
TPlayer
{
private:
char name;
int hp;
int dmg;
int wep;
public:
TPlayer(void);
~TPlayer(void);
//Naming
void SetName(char *_name);
char GetName(void);
//Health
void SetHealth(int *_hp);
int GetHealth(void);
//Damage
int SetDamage(int *_dmp)
//Weapon
void SetWeapon(int *_wep);
int GetWeapon(void);
};
#endif /* TPlayer.h */
and here is my source file:
#include "TPlayer.h"
/////////////////
// Constructor
/////////////////
TPlayer::TPlayer(void)
{
name = "";
hp = 0;
dmg = 0;
wep = 0;
}
///////////////////
// Destructor
///////////////////
~TPlayer::TPlayer()
{
delete name;
delete hp;
delete dmg;
delete wep;
}
///////////////////
// Naming
///////////////////
void SetName(char *_name)
{
name = _name;
}
char GetName(void)
{
return *name;
}
And so forth, yet its telling me that for example, name etc has not been as shown below:
TPlayer.h:4: error: function definition does not declare parameters
TPlayer.cpp:6: error: ‘TPlayer’ has not been declared
TPlayer.cpp:6: error: ISO C++ forbids declaration of ‘TPlayer’ with no type
TPlayer.cpp: In function ‘int TPlayer()’:
TPlayer.cpp:8: error: ‘name’ was not declared in this scope
TPlayer.cpp:9: error: ‘hp’ was not declared in this scope
TPlayer.cpp:10: error: ‘dmg’ was not declared in this scope
TPlayer.cpp:11: error: ‘wep’ was not declared in this scope
TPlayer.cpp: At global scope:
TPlayer.cpp:16: error: expected class-name before ‘::’ token
TPlayer.cpp: In function ‘void SetName(char*)’:
TPlayer.cpp:30: error: ‘name’ was not declared in this scope
TPlayer.cpp: In function ‘char GetName()’:
You may want to pick up a good C++ book to learn from, as the things you're getting wrong are fundamental to the language.
Class declarations need a class keyword preceeding the class name:
class TPlayer
{
private:
// ...
You need this because the compiler needs to know if you're talking about a class or a struct or a union or an enum, etc. Otherwise you end up with lots of errors like you got.
Your member functions also need to be prefixed with TPlayer::, like how you did with the constructors and destructor. These are needed so that the compiler knows that they are part of the TPlayer class.
TPlayer::TPlayer()
{
}
TPlayer::~TPlayer()
{
}
void TPlayer::SetName(char *_name)
{
}
char TPlayer::GetName(void)
{
}
There's no need to delete class members that you didn't allocate yourself.
~TPlayer::TPlayer()
{
// These are not needed. The variables name, hp, dmg, and wep
// were allocated when you created an instance of TPlayer. These
// will go away by themselves when the destructor is called.
//delete name;
//delete hp;
//delete dmg;
//delete wep;
// The exceptions to the above rule are things that are dynamically
// allocated. For example, you must delete[] everything that
// you new[]'ed, and you must fclose() all file handles you
// get from fopen(). If you consistently use the RAII idiom,
// then you won't have to worry about these "exceptions".
}
In fact, modern C++ programs nowadays rarely need to use delete in application code. The "Resource Acquisition Is Initialization" (RAII) idiom allows you to not have to worry about delete-ing things a vast majority of the time. Standard library facilities like std::vector use the RAII idiom to manage the array memory.
Note that there are rules regarding the use of identifiers beginning with underscores. You may need to be aware of them.
For the sake of learning by example, here's an valid sample class:
foo.h
#ifndef FOO_H
#define FOO_H
class Foo
{
public:
Foo();
~Foo();
void Set(int n);
int Get() const;
private:
int n;
};
#endif
foo.cpp
#include "foo.h"
Foo::Foo() : n(0)
{
}
Foo::~Foo()
{
}
void Foo::Set(int n)
{
this->n = n;
}
int Foo::Get() const
{
return n;
}
it should be class TPlayer, not TPlayer. That will confuse the compiler and there's no telling what errors you will get after it is encountered.
Also, your member function definitions need to be prefixed by TPlayer::, i.e.,
TPlayer::SetName( const char* name ) {
// ...
}
I am using Visual Studio 2008 and have two classes Parent and Child. Parent declares some static const variables in the header, which are then defined in the cpp file. When I try to use the defines as cases in a switch statement in a child class I get the error: C2051: case expression not constant. So I've done some testing and the behavior I'm seeing is somewhat inconsistent.
// Parent.h
class Parent
{
public:
Parent();
~Parent(void) { }
static const unsigned long A = 1;
static const unsigned long B;
};
// Parent.cpp
#include "Parent.h"
const unsigned long Parent::B = 2;
Parent::Parent()
{
// Everything works fine here
unsigned long l;
switch(l)
{
case A:
break;
case B:
break;
default:
break;
}
}
// Child.h
#pragma once
#include "Parent.h"
class Child :
public Parent
{
public:
Child(void);
virtual ~Child(void) { }
static const int C = 3;
static const int D;
};
// Child.cpp
#include "Child.h"
const int Child::D = 4;
Child::Child(void)
{
unsigned long l;
switch(l)
{
case A:
break;
case B: // C2051: case expression not constant
break;
case C:
break;
case D:
break;
default:
break;
}
}
I've also tried specifying Parent::B directly, which doesn't solve the issue. Is there some reason why the expression is constant in all cases except when the variable is inherited from a parent class?
You can only use a static const integer-type member variable in a constant expression if
it is initialized with a constant expression and
that constant expression is visible at the time that it is used.
In your switch, the value of Parent::A is visible because its initializer is in the Parent.h header file. The same goes for Child::C. The value of Child::D is visible because its initializer occurs earlier in Child.cpp.
However, the value of Parent::B is not visible: C++ source files are compiled separately, so when compiling Child.cpp, the compiler knows that Parent::B is a static const integer-type member variable, but it doesn't know what its value is. Thus, it can't be used in a constant expression in Child.cpp.
Note that if you ever use Parent::A as an object (e.g., &Parent::A), you will still need to define B in Parent.cpp, using const unsigned long Parent::A;, without an initializer, since you put the initializer in the class definition.
I am surprised that Visual Studio let you get away with declaring the const outside of a class declaration. The line
static const unsigned long B;
inside your Parent class should not be allowed. When I tried your example on the Mac, which uses GNU g++ compiler, I got the following error:
error: declaration of 'const long unsigned int Parent::B' outside of class is not definition
As for why it works on one class, but not the other; my guess: inside the child.cpp file, the compiler saw that D was indeed declared as a const, but it has no knowledge of how B was defined (or redefined). To make this work, you should move all constant declarations to the class in the .h file and not .cpp file.
The reason is that for the compiler the static const is not constant, beacuse at compile time it does not yet have a value, which is needed to compile the case statement.
The value is added later at link-time, when parent.o is linked to child.o (Remember that with plugins or shared libs link time could be as late as runtime).
I have the code
void switchstate(gamestates state) --line 53
{ --line 54
switch(state)
case state_title:
title();
break;
case state_about:
break;
case state_game:
break;
case state_battle:
break;
}
enum gamestates
{
state_title, state_about, state_game, state_battle,
};
int main( int argc, char* args[] )
{
gamestates currentstate = state_title;
startup();
load_resources();
switchstate(currentstate); --line 169
return 0;
}
and when I try to compile I get the errors:
\main.cpp:53: error: 'gamestates' was not declared in this scope
\main.cpp:54: error: expected ',' or ';' before '{' token
\main.cpp: In function 'int SDL_main(int, char**)':
\main.cpp:169: error: 'switchstate' cannot be used as a function
I've never used enumerations before so I'm confused on what's not working.
Generally, errors of the "<symbol> not in scope" means the compiler hasn't seen <symbol> yet. So move the declaration of gamestates to before void switchstate(...), either via an earlier #include or just moving it up in the file.
C and C++ compile from top to bottom, so symbols must be declared before they are used.
Move the declaration of the enum so it's above the switchstate function. That should do the trick. C++ is very particular about the order things are declared.
Move the enum gamestates line up in the file, before switchstate.
You may want to define the enum before the switchstate function.
In C++, you have to declare all of your types before you can refer to them. Here, you're declaring your enum after the switchstate function, so when the C++ compiler reads switchstate, it sees you refer to a type it doesn't know yet, and makes an error. If you move the enum declaration before switchstate, you should be fine.
In general, you should put declarations at the top of your file, or in seperate header files which you include at the top of the file.
Try moving definition of gamestates above the switchstate function definition.