Compile time error: undefined reference to 'CTetrisGame::Create()' - c++

I'm fairly new to programming in c++ and I've come across some code which gives me errors because the code was intended for a windows operating system, however I'm running a linux operating system. There's a file called TetrisBlock.h, which looks like:
#ifndef TETRIS_BLOCK_INCLUDED
#define TETRIS_BLOCK_INCLUDED
#include "Common.h"
class CTetrisBlock
{
public:
void Create();
void Draw();
void Destroy();
CTetrisBlock();
virtual ~CTetrisBlock();
int GetPosX();
int GetPosY();
void SetPosX(int x);
void SetPosY(int y);
private:
int m_iPosX, m_iPosY;
};
#endif
from my experience with java, this looks like an interface to me, waiting for a .cpp to implement it and fill in the abstract methods. The corresponding TetrisBlock.cpp file is as follows:
#include "TetrisBlock.h"
CTetrisBlock::CTetrisBlock()
{
int num_blocks_x = WINDOW_WIDTH / (BLOCK_SIZE + BLOCK_SPACING);
int num_blocks_y = WINDOW_HEIGHT / (BLOCK_SIZE + BLOCK_SPACING);
m_iPosX = num_blocks_x / 2;
m_iPosY = num_blocks_y - 1;
}
CTetrisBlock::~CTetrisBlock()
{
Destroy();
}
void CTetrisBlock::Create()
{
}
void CTetrisBlock::Draw()
{
tRect quad;
quad.m_iLeft = m_iPosX * (BLOCK_SIZE + BLOCK_SPACING) + BLOCK_SPACING;
quad.m_iRight = quad.m_iLeft + BLOCK_SIZE - BLOCK_SPACING;
quad.m_iTop = m_iPosY * (BLOCK_SIZE + BLOCK_SPACING) - BLOCK_SPACING;
quad.m_iBottom = quad.m_iTop - BLOCK_SIZE + BLOCK_SPACING;
glColor3d(1,1,1);
glBegin(GL_QUADS);
glVertex3f(quad.m_iLeft, quad.m_iBottom, 0);
glVertex3f(quad.m_iRight, quad.m_iBottom, 0);
glVertex3f(quad.m_iRight, quad.m_iTop, 0);
glVertex3f(quad.m_iLeft, quad.m_iTop, 0);
glEnd();
}
void CTetrisBlock::Destroy()
{
}
void CTetrisBlock::SetPosX(int x)
{
m_iPosX = x;
}
void CTetrisBlock::SetPosY(int y)
{
m_iPosY = y;
}
int CTetrisBlock::GetPosX()
{
return m_iPosX;
}
int CTetrisBlock::GetPosY()
{
return m_iPosY;
}
Note: The OpenGL library has already been imported within the common.h file
When I compile the file TetrisBlock.cpp, I get the error lines in the console:
undefined reference to 'CTetrisBlock::Create()'
undefined reference to 'CTetrisBlock::Draw()'
undefined reference to 'CTetrisBlock::Destroy()'
etc...
I'm guessing that the way I've filled in the abstract methods only works on windows, and that there's a different way to do it in linux. If this is true, then how would I fill in those abstract methods on linux. If I'm completely wrong, then can anyone explain why I'm receiving these errors. Also, are .h files always used the same way interfaces are used in java, or do they have a more general use?

Related

How to show NCursesPanel on screen by c++ bindings of NCurses

DemoI am trying out the c++ bindings shipped with ncurses-5.9. It seems that it is not easy to show a panel with window inside on screen easily. Here is my code
class SpiderApplication : NCursesApplication
{
protected:
int titlesize() const { return 2; };
void title();
public:
SpiderApplication() : NCursesApplication(TRUE) {}
int run();
};
void SpiderApplication::title()
{
const char * const titleText = "Demo";
const int len = ::strlen(titleText);
titleWindow->bkgd(screen_titles());
titleWindow->addstr(0, (titleWindow->cols() - len) / 2, titleText);
titleWindow->noutrefresh();
}
int SpiderApplication::run()
{
NCursesPanel mystd;
NCursesPanel P(mystd.lines() - titlesize(), mystd.cols(), titlesize() - 1, 0);
P.label("Demo", NULL);
P.show();
::getch();
P.clear();
return 0;
}
I suppose that the there should be a panel shown under titleline of this application. However, it doesn't. Do I miss something important here. Is there any example for how to use the c++ binding of ncurses?
Thanks.
I find the answer for my own question.
To make panel shown on screen, refresh() call cannot be omitted. Here is the working code:
NCursesPanel mystd;
NCursesPanel P(mystd.lines() - titlesize(), mystd.cols(), titlesize() - 1, 0);
P.label("Demo", NULL);
P.show();
mystd.refresh();
::getch();
P.clear();

C++ OOP Design Decisions [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I've written an aimbot for an open-source shooter called Assault Cube. Here is part of the source code:
Main.h:
/*
Control + 0 = enable aimbot
Control + 9 = enable vacuum hack
*/
#include "stdafx.h"
#ifndef MAIN_H
#define MAIN_H
#include "Player.h"
#include "Constants.h"
#include "Calculations.h"
#include <math.h>
Player players[32]; // need to give access to this to Calculations
int main() {
bool aimbotEnabled = false;
bool vacEnabled = false;
Player* closestTargetPointer = nullptr;
// [Base + DF73C] = Player 1 base
players[0] = Player(reinterpret_cast<char**>(Constants::baseAddress + 0xDF73C));
char** extraPlayersBase = *(reinterpret_cast<char***>(Constants::baseAddress + 0xE5F00));
// [Base + E5F00] = A
// [A + 0,4,8...] = Player 2/3/4... base
for (int i = 0; i < Calculations::getNumberOfPlayers() - 1; i++) {
players[i + 1] = Player(extraPlayersBase + i * 4);
}
while (true) {
if (GetAsyncKeyState(VK_CONTROL)) {
if (GetAsyncKeyState('0')) {
aimbotEnabled = !aimbotEnabled;
Sleep(500);
} else if (GetAsyncKeyState('9')) {
vacEnabled = !vacEnabled;
Sleep(500);
}
}
if (aimbotEnabled) {
closestTargetPointer = Calculations::getClosestTarget();
if (closestTargetPointer != nullptr) {
players[0].setCrosshairX(Calculations::getCrosshairHorizontalAngle(players[0], *closestTargetPointer));
players[0].setCrosshairY(Calculations::getCrosshairVerticalAngle(players[0], *closestTargetPointer));
}
}
if (vacEnabled) {
for (int i = 1; i < Calculations::getNumberOfPlayers(); i++) {
players[i].setX(players[0].getX() + 10);
players[i].setY(players[0].getY());
players[i].setZ(players[0].getZ());
}
}
Sleep(10);
}
}
#endif
Calculations.h:
#include "stdafx.h"
#ifndef CALCULATIONS_H
#define CALCULATIONS_H
#include "Player.h"
#include "Constants.h"
namespace Calculations {
/* Pythagorean's theorem applied twice for getting distance between two players in 3D space */
float getDistanceBetween(Player one, Player two) {
return sqrt(
(one.getX() - two.getX()) * (one.getX() - two.getX())
+ (one.getY() - two.getY()) * (one.getY() - two.getY())
+ (one.getZ() - two.getZ()) * (one.getZ() - two.getZ())
);
}
int getNumberOfPlayers() {
return *(reinterpret_cast<int*>(Constants::baseAddress + 0xE4E10));
}
Player* getClosestTarget() {
float smallestDistance;
int index = -1;
for (int i = 1; i < getNumberOfPlayers(); i++) {
if (players[i].getHP() > 0 && players[i].isVisible()) { // this is an error, because Calculations does not have access to the players array in Main
float tempDistance = getDistanceBetween(players[0], players[i]);
if (index == -1 || tempDistance < smallestDistance) {
smallestDistance = tempDistance;
index = i;
}
}
}
if (index == -1) {
return nullptr;
} else {
return &players[index];
}
}
float getCrosshairHorizontalAngle(Player me, Player target) {
float deltaX = target.getX() - me.getX();
float deltaY = me.getY() - target.getY();
if (target.getX() > me.getX() && target.getY() < me.getY()) {
return atanf(deltaX / deltaY) * 180.0f / Constants::pi;
} else if (target.getX() > me.getX() && target.getY() > me.getY()) {
return atanf(deltaX / deltaY) * 180.0f / Constants::pi + 180.0f;
} else if (target.getX() < me.getX() && target.getY() > me.getY()) {
return atanf(deltaX / deltaY) * 180.0f / Constants::pi - 180.0f;
} else {
return atanf(deltaX / deltaY) * 180.0f / Constants::pi + 360.0f;
}
}
float getCrosshairVerticalAngle(Player me, Player target) {
float deltaZ = target.getZ() - me.getZ();
float dist = getDistanceBetween(me, target);
return asinf(deltaZ / dist) * 180.0f / Constants::pi;
}
}
#endif
Errors:
1> Calculations.h
1>Calculations.h(26): error C2065: 'players' : undeclared identifier
1>Calculations.h(26): error C2228: left of '.getHP' must have class/struct/union
1>Calculations.h(26): error C2228: left of '.isVisible' must have class/struct/union
1>Calculations.h(27): error C2065: 'players' : undeclared identifier
1>Calculations.h(39): error C2065: 'players' : undeclared identifier
All these errors are because Calculations does not have access to the players array in Main. Is there any way I can give Calculations access to the players array?
Also, let me know if my decision of making Calculations a namespace was correct.
Add at the beginning of Calculations.h
extern Player players[32];
to tell the compiler to get the definition of players in another location / file.
The extern keyword is equivalent to declare without defining. It is a way to explicitly declare a variable, or to force a declaration without a definition...
The extern keyword declares a variable or function and specifies that
it has external linkage (its name is visible from files other than the
one in which it's defined). When modifying a variable, extern
specifies that the variable has static duration (it is allocated when
the program begins and deallocated when the program ends). The
variable or function may be defined in another source file, or later
in the same file. Declarations of variables and functions at file
scope are external by default.
Source here (+examples) and here.
Last Note : extern doesn't behave the same for functions and variables. more.
Put:
extern Player players[32];
Somewhere before line 26 of Calculations.h.
Having a global player array, as it would be with the extern keyword, is certainly not a good design decision.
A better design would probably define a world object that knows about anything that is currently in existence and could define what information is available to which actor. Players would then query this world object for information on their surrounding and make decisions based on that.
You might want to implement this world as a singleton, so that you can write static wrapper functions that silently supply the object to the calls, avoiding the hassle to look up the world object everywhere.

NLOpt with windows forms

I am suffering serious problems while trying to use nlopt library (http://ab-initio.mit.edu/wiki/index.php/NLopt_Tutorial) in windows forms application. I have created following namespace which runs perfectly in console application.
#include "math.h"
#include "nlopt.h"
namespace test
{
typedef struct {
double a, b;
} my_constraint_data;
double myfunc(unsigned n, const double *x, double *grad, void *my_func_data)
{
if (grad) {
grad[0] = 0.0;
grad[1] = 0.5 / sqrt(x[1]);
}
return sqrt(x[1]);
}
double myconstraint(unsigned n, const double *x, double *grad, void *data)
{
my_constraint_data *d = (my_constraint_data *) data;
double a = d->a, b = d->b;
if (grad) {
grad[0] = 3 * a * (a*x[0] + b) * (a*x[0] + b);
grad[1] = -1.0;
}
return ((a*x[0] + b) * (a*x[0] + b) * (a*x[0] + b) - x[1]);
}
int comp()
{
double lb[2] = { -HUGE_VAL, 0 }; /* lower bounds */
nlopt_opt opt;
opt = nlopt_create(NLOPT_LD_MMA, 2); /* algorithm and dimensionality */
nlopt_set_lower_bounds(opt, lb);
nlopt_set_min_objective(opt, myfunc, NULL);
my_constraint_data data[2] = { {2,0}, {-1,1} };
nlopt_add_inequality_constraint(opt, myconstraint, &data[0], 1e-8);
nlopt_add_inequality_constraint(opt, myconstraint, &data[1], 1e-8);
nlopt_set_xtol_rel(opt, 1e-4);
double x[2] = { 1.234, 5.678 }; /* some initial guess */
double minf; /* the minimum objective value, upon return */
int a=nlopt_optimize(opt, x, &minf) ;
return 1;
}
}
It optimizes simple nonlinear constrained minimization problem. The problem arises when I try to use this namespace in windows form application. I am constantly getting unhandled exception in myfunc which sees "x" as empty pointer for some reason and therefore causes error when trying to access its location. I believe that the problem is somehow caused by the fact that windows forms uses CLR but I dont know if it is solvable or not. I am using visual studio 2008 and the test programs are simple console project (which works fine) and windows forms project (that causes aforementioned errors).
My test code is based on tutorial for C from the provided link. I although tried C++ version which once again works fine in console application but gives debug assertion failed error in windows forms application.
So I guess my questions is : I have working windows forms application and I would like to use NLOpt. Is there a way to make this work ?

Code requires too much memory

I'm porting some code to another structure:
class EnvironObject
{
protected:
vector<float> mX, mY, mXSpeed, mYSpeed;
int mMaxObjects;
public:
virtual void init(int maxObjects);
virtual void setLimit(int limit);
virtual int getLimit();
virtual void update(float arg) = 0;
};
void EnvironObject::setLimit(int limit)
{
mMaxObjects = limit;
mX.resize(limit, 0); mY.resize(limit, 0);
mXSpeed.resize(limit, 0); mY.resize(limit, 0);
}
int EnvironObject::getLimit()
{
return mMaxObjects;
}
void EnvironObject::init(int maxObjects)
{
mX = mY = mXSpeed = mYSpeed = std::vector<float>(mMaxObjects);
fill(mX.begin(), mX.end(), 0);
fill(mY.begin(), mY.end(), 0);
fill(mXSpeed.begin(), mXSpeed.end(), 0);
fill(mYSpeed.begin(), mYSpeed.end(), 0);
/*mX.reserve(mMaxObjects * 1.5); mY.reserve(mMaxObjects * 1.5);
mXSpeed.reserve(mMaxObjects * 1.5); mYSpeed.reserve(mMaxObjects * 1.5);*/
mMaxObjects = maxObjects;
}
This is some basic class, now it's usage:
class Rain : public EnvironObject
{
public:
Rain(int maxDrops = 150);
void update(float windPower);
};
Rain::Rain(int maxDrops)
{
srand(time(NULL));
IEnvironObject::init(maxDrops);
}
void Rain::update(float windPower)
{
for (int i=0; i < mMaxObjects; i++)
{
mX[i] += mXSpeed[i];
mY[i] += mYSpeed[i];
mXSpeed[i] += windPower;
mYSpeed[i] += G;
// Drawing
}
}
The objects Rain creates with default constructor (so, each array is 150 elements size) and then I'm calling setLimit(50).
The problem is that code fails almost each running with exception:
terminate called after throwing an instance of 'std::bad_alloc'
And sometimes it segfaults at line:
mY[i] += mYSpeed[i];
I can't image what could it be, because the code is old and it worked. The new one is only base class.
And when I'm looking at RAM usage when starting app, I see almost +600 mb!
Look again at that function of yours:
void EnvironObject::init(int maxObjects)
{
mX = mY = mXSpeed = mYSpeed = std::vector<float>(mMaxObjects);
// ^
// ...
mMaxObjects = maxObjects;
}
You're using a not yet initialized variable.
A big problem with your class is that you are doing what's called two-phase construction. Your class EnvironObject has a compiler-supplied default constructor that creates an object with random values for all POD types (mMaxObjects). Users then need to call the init() method to really initialize the object. But that's what constructors are there for!
void EnvironObject::EnvironObject(int maxObjects)
: mMaxObjects(maxObjects)
, mX(maxObjects), mY(maxObjects), mXSpeed(maxObjects), mYSpeed(maxObjects)
{
/* these aren't necessary, std::vector automatically does this
fill(mX.begin(), mX.end(), 0);
fill(mY.begin(), mY.end(), 0);
fill(mXSpeed.begin(), mXSpeed.end(), 0);
fill(mYSpeed.begin(), mYSpeed.end(), 0);
*/
}
Derived classes can then use this constructor:
Rain::Rain(int maxDrops)
: EnvironObject(maxDrops)
{
srand(time(NULL));
}
Regarding this crash in the subscription mY[i] += mYSpeed[i]:
This might happen when you are calling this function through a pointer that's pointing to nowhere.
You're using mMaxObjects in init() before initializing it. So it has a random value.
void EnvironObject::init(int maxObjects)
{
mX = mY = mXSpeed = mYSpeed = std::vector<float>(mMaxObjects); // you mean maxObjects here
I think you want to replace
void EnvironObject::init(int maxObjects)
{
mX = mY = mXSpeed = mYSpeed = std::vector<float>(mMaxObjects);
with
void EnvironObject::init(int maxObjects)
{
mX = mY = mXSpeed = mYSpeed = std::vector<float>(maxObjects);
Notice the replacement of mMaxObject to maxObjects in the vector creation.
One comment, though it won't likely fix your memory error, is that since the fields mX, mY, mXSpeed, and mYSpeed seem related and the vectors are all the same size, you should consider merging them into one structure with four members, and having a single vector containing several of those structure instances.

Inherited variables are not reading correctly when using bitwise comparisons

I have a few classes set up for a game, with XMapObject as the base, and XEntity, XEnviron, and XItem inheriting it.
MapObjects have a number of flags, one of them being MAPOBJECT_SOLID. My problem is that XEntity is the only class that correctly detects MAPOBJECT_SOLID. Both Items are Environs are always considered solid by the game, regardless of the flag's state. What is important is that Environs and Item should almost never be solid.
Each class has a very basic preliminary constructor, just initializing all varibles to zero or NULL. During the CreateX() phase, Objects are linked into the map, set into a linked linked list.
Both XItem and XEnviron are a tad sloppy. They are both new, and in the middle or my debugging attempts.
Here are the relevent code samples:
XMapObject:
#define MAPOBJECT_ACTIVE 1
#define MAPOBJECT_RENDER 2
#define MAPOBJECT_SOLID 4
class XMapObject : public XObject
{
public:
Uint8 MapObjectType,Location[2],MapObjectFlags;
XMapObject *NextMapObject,*PrevMapObject;
XMapObject();
void CreateMapObject(Uint8 MapObjectType);
void SpawnMapObject(Uint8 MapObjectLocation[2]);
void RemoveMapObject();
void DeleteMapObject();
void MapObjectSetLocation(Uint8 Y,Uint8 X);
void MapObjectMapLink();
void MapObjectMapUnlink();
};
XMapObject::XMapObject()
{
MapObjectType = 0;
Location[0] = 0;
Location[1] = 1;
NextMapObject = NULL;
PrevMapObject = NULL;
}
void XMapObject::CreateMapObject(Uint8 Type)
{
MapObjectType = Type;
}
void XMapObject::SpawnMapObject(Uint8 MapObjectLocation[2])
{
if(!(MapObjectFlags & MAPOBJECT_ACTIVE)) { MapObjectFlags += MAPOBJECT_ACTIVE; }
Location[0] = MapObjectLocation[0];
Location[1] = MapObjectLocation[1];
MapObjectMapLink();
}
XEntity:
XEntity *StartEntity = NULL,*EndEntity = NULL;
class XEntity : public XMapObject
{
public:
Uint8 Health,EntityFlags;
float Speed,Time;
XEntity *NextEntity,*PrevEntity;
XItem *IventoryList;
XEntity();
void CreateEntity(Uint8 EntityType,Uint8 EntityLocation[2]);
void DeleteEntity();
void EntityLink();
void EntityUnlink();
Uint8 MoveEntity(Uint8 YOffset,Uint8 XOffset);
};
XEntity::XEntity()
{
Health = 0;
Speed = 0;
Time = 1.0;
EntityFlags = 0;
NextEntity = NULL;
PrevEntity = NULL;
IventoryList = NULL;
}
void XEntity::CreateEntity(Uint8 EntityType,Uint8 EntityLocation[2])
{
CreateMapObject(EntityType);
SpawnMapObject(EntityLocation);
if(!(MapObjectFlags & MAPOBJECT_SOLID) { MapObjectFlags += MAPOBJECT_SOLID; }
EntityFlags = ENTITY_CLIPPING;
Time = 1.0;
Speed = 1.0;
EntityLink();
}
void XEntity::EntityLink()
{
if(StartEntity == NULL)
{
StartEntity = this;
PrevEntity = NULL;
NextEntity = NULL;
}
else
{
EndEntity->NextEntity = this;
}
EndEntity = this;
}
XEnviron:
class XEnviron : public XMapObject
{
public:
Uint8 Effect,TimeOut;
void CreateEnviron(Uint8 Type,Uint8 Y,Uint8 X,Uint8 TimeOut);
};
void XEnviron::CreateEnviron(Uint8 EnvironType,Uint8 Y,Uint8 X,Uint8 TimeOut)
{
CreateMapObject(EnvironType);
Location[0] = Y;
Location[1] = X;
SpawnMapObject(Location);
XTile *Tile = GetTile(Y,X);
Tile->Environ = this;
MapObjectFlags = MAPOBJECT_ACTIVE + MAPOBJECT_SOLID;
printf("%i\n",MapObjectFlags);
}
XItem:
class XItem : public XMapObject
{
public:
void CreateItem(Uint8 Type,Uint8 Y,Uint8 X);
};
void XItem::CreateItem(Uint8 Type,Uint8 Y,Uint8 X)
{
CreateMapObject(Type);
Location[0] = Y;
Location[1] = X;
SpawnMapObject(Location);
}
And lastly, the entity move code. Only entities are capable of moving themselves.
Uint8 XEntity::MoveEntity(Uint8 YOffset,Uint8 XOffset)
{
Uint8
NewY = Location[0] + YOffset,
NewX = Location[1] + XOffset;
if((NewY >= 0 && NewY < MAPY) && (NewX >= 0 && NewX < MAPX))
{
XTile *Tile = GetTile(NewY,NewX);
if(Tile->MapList != NULL)
{
XMapObject *MapObject = Tile->MapList;
while(MapObject != NULL)
{
if(MapObject->MapObjectFlags & MAPOBJECT_SOLID)
{
printf("solid\n");
return 0;
}
MapObject = MapObject->NextMapObject;
}
}
if(Tile->Flags & TILE_SOLID && EntityFlags & ENTITY_CLIPPING)
{
return 0;
}
this->MapObjectSetLocation(NewY,NewX);
return 1;
}
return 0;
}
What is wierd, is that the bitwise operator always returns true when the MapObject is an Environ or an Item, but it works correctly for Entities. For debug I am using the printf "Solid", and also a printf containing the value of the flag for both Environs and Items.
Any help is greatly appreciated, as this is a major bug for the small game I am working on. I am also very new at Object Oriented programming, anything tips, suggestions and/or criticism are also welcome.
Your problem appears to be that you never initialize MapObjectFlags in any classes other than XEnviron so, as a basic type, it will have an unspecified value in XItem, XEntity and other XMapObject derived objects. I suggest that, as a member of XMapObject you explicitly initialize it to a known value.
As a rule, it is generally a good idea to ensure that all members of basic type are explicitly initialized in the initializer list of every constructor that you define.
e.g.
XMapObject()
: MapObjectFlags(0)
, // ... other initializers
{
// Other initializations
}
You can't (legally) be calling XEntity::MoveEntity on a MapObject or Environ because they don't have such a method. If you're using static_cast to change your object pointer into an XEntity so you can call MoveEntity on it, then you really have no guarantees about how the bit operation will work. In some implementations, things may appear to work in MoveEntity, but what's actually happening is it's interpreting the other object's memory as an XEntity. When it tries to access the offset where it believes MapObjectFlags exists, it's not actually there and always has that bit set to 1.
I figured out the problem earlier today - It didn't have any relation to OO programming, inheritance, or bitwise; it was a simple scope error.
The problem was in the fact that during my quick test to get an Environ in game, I declared the new variable inside of the control switch sequence, so the next time any control was used, the Environ would act in unpredictable ways.
switch(Event.key.keysym.sym)
{
...
case SDLK_c: { XEnviron Environ; Environ.InitEnviron(...); }
...
}