I would like this mov() virtual member function to get() the coordinates x,y
However there is this error which doesn't make sense at all
pirate.o:: In function 'ZN6Pirate3movEPS_PA100_3Sea':|
pirate.cpp:: undefined reference to `Ship::getX() const' (line 7)
getX() is inherited
Parent Class:Ship, Derived class:Pirate
Ship.h
#ifndef SHIP_H
#define SHIP_H
#include <iostream>
#include "sea.h"
#define SIZE 100
class Ship
{
private:
int x,y; //Coordinates of ship
public:
Ship(){}
virtual void func()=0;
virtual void mov()=0;
protected:
int getX()const;
int getY()const;
};
#endif
Ship.cpp
#include "Ship.h"
int Ship::getX()const
{return x;}
int Ship::getY()const
{return y;}
virtual void func()=0;
virtual void mov()=0;
Pirate.h
#ifndef PIRATE_H
#define PIRATE_H
#include "ship.h"
#include "sea.h"
class Pirate : public Ship
{
protected:
void func();
void mov(Pirate * ship , Sea Map[SIZE][SIZE]);
};
#endif
Pirate.cpp
#include "pirate.h"
void Pirate::func(){}
void Pirate::mov(Pirate* ship , Sea Map[SIZE][SIZE])
{
int x_ref = ship->getX();
int y_ref = ship->getY();
}
Sea.h
#ifndef SEA_H
#define SEA_H
#include "ship.h"
class Sea
{
private:
bool hasShip;
public:
Sea(){hasShip=0;}
bool gethasShip()const{return hasShip;}
void sethasShip(bool i){hasShip = i;}
};
#endif
The other answer is exactly right. If you remove those two lines it will compile correctly, and the error you're getting (and the fact that you're not getting other errors) is due to the fact that Ship.cpp is not properly included in the compilation process.
I'm not sure if you have access to Visual Studio 2013, but if you do, I tested it to be sure with the following solution/project: http://filebin.ca/1i9z9TwF2kf5/Pirates.zip
You forgot to compile and link Ship.cpp
I can tell this because if you'd tried to compile it then you'd have got an error here:
virtual void func()=0;
virtual void mov()=0;
That's not valid C++, you don't define pure virtuals like that (you don't need to define them at all unless they are destructors or you call them explicitly)
If you don't link with the file with the definition of Ship::getX() const then it's not surprising that the linker tells you it's undefined.
Related
I'm implementing hardware drivers for an embedded C/C++ project, and trying to make things a bit more flexible for future projects.
I have the vast majority of the work done in LCD.hpp/LCD.cpp, where there's a class that has five virtual functions. Four of these are for twiddling GPIO pins and sending SPI messages, and the fifth is for implementing various fonts. A shortened class declaration is as follows:
//LCD.hpp
#include <cstdint>
#ifndef LCD_HPP
#define LCD_HPP
class LCD {
public:
virtual void write_character(char what) = 0; //Stores data into a buffer in LCD through another function
protected:
virtual void SPI_TX(uint8_t *TXData, uint8_t length, bool ToBeContinued) = 0;
virtual void update_RST(bool pinstate) = 0;
virtual void update_DC(bool pinstate) = 0;
virtual void update_backlight(uint8_t brightness) = 0;
};
#endif
Moving on, I implemented a font-printing write_character as such.
//LCD_FixedWidth.hpp
#include <cstdint>
#include "LCD.hpp"
#ifndef LCD_FIXEDWIDTH_HPP
#define LCD_FIXEDWIDTH_HPP
class LCD_FixedWidth : virtual public LCD {
public:
void write_character(char what);
};
#endif
Now it's time for the various hardware bits.
//LCD_hardware.hpp
#include <cstdint>
#include "LCD.hpp"
#include "LCD_FixedWidth.hpp"
#ifndef LCD_HARDWARE_HPP
#define LCD_HARDWARE_HPP
class LCD_hardware : virtual public LCD {
protected:
void SPI_TX(uint8_t *TXData, uint8_t length, bool ToBeContinued);
void update_RST(bool pinstate);
void update_DC(bool pinstate);
void update_backlight(uint8_t brightness);
};
And then a class to tie it all together, still in LCD_hardware.hpp...
class LCD_meta : public LCD_hardware, public LCD_FixedWidth {
public:
void write_character(char what) { LCD_FixedWidth::write_character(what); };
protected:
void SPI_TX(uint8_t *TXData, uint8_t length, bool ToBeContinued) { LCD_hardware::SPI_TX(TXData, length, ToBeContinued); };
void update_RST(bool pinstate) { LCD_hardware::update_RST(pinstate); };
void update_DC(bool pinstate) { LCD_hardware::update_DC(pinstate); };
void update_backlight(uint8_t brightness) { LCD_hardware::update_backlight(brightness); };
};
#endif
And for all of this, I get a multiple definition of LCD_FixedWidth::write_character(char) error. Anybody see anything I'm missing here? All of my headers are guarded properly, and I can only see one implementation of write_character...
This was caused by having LCD_meta and LCD_hardware in the same header file. The code for the LCD_hardware functions was in an implementation file, so the LCD_meta class didn't actually have those functions defined yet... One class per file!
just getting an odd error and I'm not entirely sure as to why.
I have 4 files (two headers and two implementations). The issue is inside the headers:
The main file ONLY includes the Station.h, which is why Stations.h is included inside it.
Station.h
#ifndef STATION_H
#define STATION_H
#include "Stations.h"
#include <string>
enum PassType{student, adult};
class Station{
std::string station_name;
unsigned int student_passes;
unsigned int adult_passes;
public:
Station();
void set(const std::string&, unsigned, unsigned);
void update(PassType, int);
unsigned inStock(PassType) const;
const std::string& getName() const;
};
#endif
Stations.h
#ifndef STATIONS_H
#define STATIONS_H
#include "Station.h"
namespace w2{
class Stations{
Station *station;
public:
Stations(char *);
void update() const;
void restock() const;
void report() const;
~Stations();
};
}
#endif
It doesn't know what Station is. I'm getting the following error:
./Stations.h:9:2: error: unknown type name 'Station'; did you mean 'Stations'?
Station *station;
What exactly am I missing here?
You are #includeing Stations.h in Station.h. As a result, the compiler sees class Stations before class Station. In this case, it doesn't appear that Station requires Stations, so you can simply remove the include.
If Station did need to know about Stations, then you'd have to use a forward declaration in one of the headers or the other (and be careful not to use the forward-declared class in a way that required the full definition).
Don't forget to put a semicolon after you declare the Stations class:
class Stations {
Station *station;
};
U need to do the forward declaration.
Remove the #include "Stations.h" from the Station.h
#ifndef STATIONS_H
#define STATIONS_H
#include "Station.h"
namespace w2{
class Station;
class Stations{
Station *station;
public:
Stations(char *);
void update() const;
void restock() const;
void report() const;
~Stations();
};
}
#endif
I want to compile the Rigi source code but I get some error while compiling:
adt/object.h: At global scope:
adt/object.h:35:18: error: ‘class RigiObject RigiObject::RigiObject’ is inaccessible
adt/chararray.h:51:13: error: within this context
make: *** [cl_arcflags.o] Error 1
Here our two files.
object.h:
#ifndef OBJECTH
#define OBJECTH 1
#include <stdio.h>
#ifndef STREAM_H
#include <iostream>
#endif
#ifndef __STRING_H
#include <string.h>
#endif
#ifndef __STDLIB_H
#include <stdlib.h>
#endif
#ifndef _CCHEADER_H_
#include "CCheader.h"
#endif
extern char* indent_line(int);
class RigiObject;
typedef RigiObject* ObjectPtr;
#define Oberr(a) fprintf(stderr,"ERROR :: Generic Object Routine Called :: %s\n","a");
class RigiObject {
public:
RigiObject() {/*Oberr(RigiObject)*/;}
~RigiObject() {/*Oberr(~RigiObject)*/;}
// Routines that are really described by the Derived Classes
virtual int Printout(int) const
{Oberr(printout); return (int) 0;}
virtual unsigned int Hash() const
{Oberr(hash); return (unsigned int) 0; }
virtual RigiBool isEqual(void* a) const
{Oberr(isEqual); a = NIL;
(void) abort();
return (RigiBool) RigiFalse;}
virtual void Delete_class(ObjectPtr)
{Oberr(delete_type);}
virtual void* Create_class();
virtual void* Duplicate_class();
};
#endif
and chararray.h:
#ifndef CHARARRAYH
#define CHARARRAYH
#ifndef ARRAYOBIDH
#include "array.h"
#endif
#ifndef CHARTYPEH
#include "chartype.h"
#endif
class CharArray;
typedef CharArray* CharArrayPtr;
class CharArray : public Array {
int slot;
public:
// Routines to initialize and destroy the class.
CharArray(unsigned int size = CLTN_DEFAULT_CAPACITY);
CharArray(const CharArray&);
~CharArray();
// Functions that are Required to Use this Class as an Object
// .... all routines the same as in Class Array.......
// Routines that are required by a Collection class and derived classes
// of Collections. [See Array Class for these routines.]
virtual unsigned int size() const {return slot;}
// .... all routines the same as in Class Array.......
// Routines specific to this class
void operator=(const CharArray&);
RigiBool operator==(const CharArray&) const;
void Create(char*);
void Create(char*,int);
void Create(int, char*);
void Add(char*);
void Add(CharType&);
void Addob(RigiObject& ob)
{Array::Add(slot++,&ob);}
void Append(char*);
char* Concat(char);
int FindIndex(char*);
char* Remove()
{return ((CharTypePtr)Array::Remove(--slot))->string();}
ObjectPtr Pop()
{return (Array::Remove(--slot));}
ObjectPtr Look(int i)
{return (Array::At(i));}
void Empty();
virtual unsigned int Size() const
{return slot;}
char* Peek();
char* At(int);
};
#endif
What's wrong with the code?
Assuming that the type RigiBool in the declaration RigiBool operator==(const CharArray&) const; is not defined in one of the headers "array.h" "chartype.h" I think you should include the header containing definition of the type, and just to be sure the "object.h" too.
For cases where a header file uses values of class type variables (not pointers and references) it is recommended to include the headers that contain the class definition. Otherwise a simple forward declaration should be enough.
The types RigiBool, RigiObject and ObjPtr are not available in chararray.h: you need to include object.h (plus whatever else defines RigiBool if CCHeader.h doesn't) -- similarly for RigiBool and RigiFalse in object.h
// somewhere at the top of chararray.h
#include "object.h"
Note: if you define virtual member functions in RigiObject, you should declare the destructor virtual as well
Note: You already have include guards in the #included headers, no need to put them around the #include directives -- doing otherwise indicates (falsely in your case) that you are doing conditional compiling
//chararray.h
#ifndef CHARARRAYH
#define CHARARRAYH
#include "array.h"
#include "chartype.h"
...
//object.h
#ifndef OBJECTH
#define OBJECTH
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include "CCheader.h"
...
It's hard to say from the little information but I would assume RigiBool is a derived class of RigiObject? When you now reference RigiBool in chararray.h it has to know the RigiObject base class but the RigiObject also needs to know about RigiBool. So you can't declare the base class without knowing the derived RigiBool. Try if forward declaring RigiBool in object.h helps to break the cycle.
I asked a while ago how to use virtual classes in c++, and to my dismay i learned that you can't. But one user,(namely "Emilio Garavaglia" thanks a bunch), posted a way to get something similar to virtual classes, just with some extra code. however, i'm having some trouble getting what i'm doing to compile. here's the code:
global_defs.h
#define Interface class
#define abstract_class class
#define implements : public
I_Graphics.h
#ifndef I_GRAPHICS_H
#define I_GRAPHICS_H
#include <string>
#include "global_defs.h"
Interface I_Graphics
{
public:
virtual ~I_Graphics() {};
virtual void Initialize() = 0;
virtual void Frame() = 0;
virtual void Shutdown() = 0;
class I_Model;
virtual I_Model * CreateModel() = 0;
};
Interface I_Graphics::I_Model
{
public:
virtual ~I_Model() {}
virtual void Initialize(std::string const & filename, std::string const & textureFilename) = 0;
virtual void * GetVertexBuffer() = 0;
virtual void * GetIndexBuffer() = 0;
};
#endif
Graphics.h
#ifndef GRAPHICS_H
#define GRAPHICS_H
#include "global_defs.h"
#include <map>
#include <string>
#include <memory>
#include "I_Graphics.h"
class Graphics implements I_Graphics
{
public:
Graphics();
~Graphics();
void Initialize();
void Frame();
void Shutdown();
class Model;
I_Model * CreateModel() {return new Model;} // <--- compile error here
private:
std::map <std::string, I_Model *> m_ModelList;
};
class Graphics::Model implements I_Graphics::I_Model
{
public:
Model();
~Model();
void Initialize(std::string filename, std::string textureFilename);
void * GetVertexBuffer();
void * GetIndexBuffer();
};
#endif
Graphics.cpp
nothing going here, havn't really started working on the hard part yet, just trying to get the model instantiation to work.
#include "Graphics.h"
Graphics::Graphics()
{
}
Graphics::~Graphics()
{
}
void Graphics::Initialize()
{
}
void Graphics::Frame()
{
}
void Graphics::Shutdown()
{
}
Graphics::Model::Model()
{
}
Graphics::Model::~Model()
{
}
void Graphics::Model::Initialize(std::string filename, std::string textureFilename)
{
}
void * Graphics::Model::GetVertexBuffer()
{
return NULL;
}
void * Graphics::Model::GetIndexBuffer()
{
return NULL;
}
so, as the little comment says, i get an error there saying:
error C2512: 'Graphics::Model' : no appropriate default constructor available
when there obviously is a constructor for it in graphics.cpp . Can someone please explain what the compiler is complaining about here?
EDIT:
not sure if it means anything, but when mousing over the little red squiggle in MSVC, it says, "object of abstract class type Graphics::Model is not allowed" . ...but it doesn't have any pure virtual members, so it's not abstract right?
EDIT:
On the suggestion of Castilho, i declare CreateModel in graphics.h like before, but then defined it in graphics.cpp, and it yielded a much more specific error, but i still don't understand why.
error C2259: 'Graphics::Model' : cannot instantiate abstract class
1> due to following members:
1> 'void I_Graphics::I_Model::Initialize(const std::string &,const std::string &)' : is abstract
1> i_graphics.h(28) : see declaration of 'I_Graphics::I_Model::Initialize'
You're using the Model class before it is defined. Define the function CreateModel in a separate CPP and it may work.
I tried to look at the similar problems listed here on Stackoverflow and on Google but they deal mostly with templates and that's not my case. I'm using GCC 4.4.5 on Debian Testing 64bit.
So, I have two classes - CEntity:
#ifndef CENTITY_H_INCLUDED
#define CENTITY_H_INCLUDED
#include "global_includes.h"
// game
#include "CAnimation.h"
#include "Vars.h"
#include "vector2f.h"
#include "Utils.h"
class CAnimation;
class CEntity
{
public:
CEntity();
virtual ~CEntity();
void _update(Uint32 dt);
void updateAnimation(Uint32 dt);
void addAnimation(const std::string& name, CAnimation* anim);
void addAnimation(const std::string& name, const CAnimation& anim);
void removeAnimation(const std::string& name);
void clearAnimations();
bool setAnimation(const std::string& name);
SDL_Surface* getImage() const;
const vector2f& getPos() const;
const vector2f& getLastPos() const;
F getX() const;
F getY() const;
F getLastX() const;
F getLastY() const;
SDL_Rect* getHitbox() const;
SDL_Rect* getRect() const;
F getXSpeed() const;
F getYSpeed() const;
void setPos(const vector2f& pos);
void setPos(F x, F y);
void setPos(F n);
void setX(F x);
void setY(F y);
void setHitboxSize(int w, int h);
void setHitboxSize(SDL_Rect* rect);
void setHitboxWidth(int w);
void setHitboxHeight(int h);
void setSpeed(F xSpeed, F ySpeed);
void setXSpeed(F xSpeed);
void setYSpeed(F ySpeed);
void stop();
void stopX();
void stopY();
void affectByGravity(bool affect);
void translate(const vector2f& offset);
void translate(F x, F y);
bool collide(CEntity& s);
bool collide(CEntity* s);
protected:
CAnimation* mCurrentAnimation;
SDL_Surface* mImage;
vector2f mPos;
vector2f mLastPos;
SDL_Rect* mHitbox; // used for collisions
SDL_Rect* mRect; // used only for blitting
F mXSpeed;
F mYSpeed;
bool mAffByGrav;
int mHOffset;
int mVOffset;
private:
std::map<std::string, CAnimation*> mAnims;
};
#endif // CENTITY_H_INCLUDED
and CPlayerChar which inherits from CEntity:
#ifndef CPLAYERCHAR_H_INCLUDED
#define CPLAYERCHAR_H_INCLUDED
#include "global_includes.h"
// game
#include "CEntity.h"
class CEntity;
class CPlayerChar : public CEntity
{
public:
CPlayerChar();
virtual ~CPlayerChar();
virtual void update(Uint32 dt) = 0;
virtual void runLeft() = 0;
virtual void runRight() = 0;
virtual void stopRunLeft() = 0;
virtual void stopRunRight() = 0;
virtual void attack() = 0;
virtual void stopAttack() = 0;
virtual void attack2() = 0;
virtual void stopAttack2() = 0;
virtual void ground() = 0;
virtual void midair() = 0;
void jump();
void stopJump();
protected:
// looking right?
bool mRight;
bool mJumping;
bool mOnGround;
bool mGrounded;
};
#endif // CPLAYERCHAR_H_INCLUDED
When I try to compile it, GCC throws this error:
CPlayerChar.h:12: error: invalid use of incomplete type ‘struct CEntity’
CPlayerChar.h:9: error: forward declaration of ‘struct CEntity’
I tried it first without the forward declaration 'class CEntity;' in CPlayerChar.h on line 9, but then it would throw this instead
CPlayerChar.h:12: error: expected class-name before ‘{’ token
So the forward declaration has to be there. Also, CEntity is clearly a class, not a struct.
You have a circular inclusion in your header files.
But without all the header files we will not be able to fix it.
I would start here.
#include "CAnimation.h"
Looking at your header you don't actually need this. You only use CAnimation by reference or pointer so the forward declaration you have should be sufficient. Move the include into the source file (ie out of the header).
The next place I would look is:
#include "global_includes.h"
Any global includes that are included in a header file better be very simple. Should only contain simple types and not include any other header files (unless they are just as simple). Anything complex is going to lead to problems with circular dependencies.
General rule of thumb
A header file should only include header files that it absolutely needs. Otherwise they should be included from the source file. You only absolutely need a header file if it defines a class that is used as a parent class you have members objects of that class, or you use parameter objects of that class.
I use the term object to distinguish from references or pointers. If you are using these you do not need to include the header file. You only need to do a forward declaration.
You probably have got a loop in your includes in such way that CPlayerChar doesnt know who really is CEntity, it just knows that it exists, but doesnt know what is it.
If you remove the "class CEntity" declaration, you will see that GCC will complain that CEntity doesnt exists.
You must check that nothing that CEntity includes include CPlayerChar.
You have to ensure that the full definition of the class CEntity is visible at the point where you define the class CPlayerChar. (So check your inclusions.)
This is because you can only inherit from fully defined classes, but not from just forward-declared ones.
The only time you can get away with forward-declarations in place of full definitions is when you make pointers or references to a type, but only if you never access any of its members, or (thanks to #Alf) when declaring a function with incomplete return type.