I am a little bit stumped on this at the moment, From what i understand, the specific enemies inherit from the base enemy class, so when created they use the base enemy constructor, to create their own objects copies of the variables to work with. so when i use the inherited enemy's set_E function wound`t that set its own E_Damage and E_Health to work with? and if so why is it denying access to its own variables?
In the locals tab on visual basic each x object does indeed have its own enemy variables, if i try direct access to the enemy class i get an access error, if i try use the objects own i also get this error, what am i doing wrong?
Base enemy class
class Enemy
{
public:
Enemy();
~Enemy();
void set_E(float, float);
float get_E_H();
float get_E_D();
virtual void Battle() = 0;
float* E_Damage;
float* E_Health;
char* E_Descrip;
float* E_Attack;
};
Enemy distructor
Enemy::~Enemy()
{
if (E_Damage != nullptr)
{
delete E_Damage;
E_Damage = nullptr;
}
if (E_Health != nullptr)
{
delete E_Health;
E_Health = nullptr;
}
if (E_Attack != nullptr)
{
delete E_Attack;
E_Attack = nullptr;
}
if (E_Descrip != nullptr)
{
delete E_Descrip;
E_Descrip = nullptr;
}
}
Enemy Constructor:
E_Damage = new float;
E_Damage = nullptr;
E_Health = new float;
E_Health = nullptr;
E_Attack = new float;
E_Attack = nullptr;
Example inherited enemy.h
class T_Rex : private Enemy, private CS_Text_Adventure
{
public:
void T_Rex::set_E(float Dmg, float Health, T_Rex x);
T_Rex();
~T_Rex();
void Battle() override;
};
Example inherited enemy.cpp
void T_Rex::Battle()
{
T_Rex x;
x.set_E(15.0f, 100.0f, x);
E_Descrip = "the passage way opens up to a tropical forrest";
std::cout << std::endl;
std::cout << x.E_Descrip << std::endl;
std::cout << std::endl;
while(*fight == true)
{
*x.E_Attack = rand() % 100 + 0;
if(*x.E_Attack >= 30)
{
*P_Health -= *x.E_Damage;
}
else if(*x.E_Attack < 30)
{
*x.E_Health -= *P_Health;
}
if(*P_Health <= 0)
{
*gamerun = false;
}
else if(*E_Health <= 0)
{
*fight = false;
}
}
step++;
}
Unauthorized access on the pointer deference reassign:
void T_Rex::set_E(float Dmg, float Health, T_Rex x)
{
*x.E_Damage = Dmg;
*x.E_Health = Health;
}
Lets take these two lines from your constructor:
E_Damage = new float;
E_Damage = nullptr;
First you allocate a single float, and make E_Damage point to it. Then you immediately make E_Damage a null pointer, so it no longer points anywhere valid. This leads to a memory leak.
Later you use this null pointer, which leads to undefined behavior and possible crashes.
For single values there's seldom a need to use pointers at all, especially in this case. Just declare E_Damage (and the other member variables) as normal non-pointer variables.
Related
I'm trying to create a Monopoly game in C++ and I've been messing with object-oriented-programming, the problem happens with the classes "Game" and "Player", I would like to know how to use "Game"'s functions inside "Player" and "Player"'s functions inside "Game", but I've been getting a compiler error saying that the class is not defined.
Switching class positions won't work (obviously) but I tried anyways.
Code (reduced and minimized to the Game and Player classes):
namespace Monopoly {
typedef enum { normal, train, company, incometax, luxurytax, start, chancecard, chestcard, jail } type;
class Game {
private:
bool running = false;
int turn = 1;
int currentPlayerID;
int startingMoney = 1000;
std::vector<Player> players;
public:
// Functions
void createPlayer() {
++currentPlayerID;
Player newPlayer(currentPlayerID, startingMoney);
players.push_back(newPlayer);
++currentPlayerID;
}
void createPlayers(int playerAmount) {
for (int i = 0; i <= playerAmount; ++i) {
createPlayer();
}
}
Player getPlayer(int index) {
Player p = players[index];
return p;
}
};
class Player {
private:
int playerID;
int money;
std::vector<int> propertiesOwned;
void addProperty(int id) {
this->propertiesOwned.push_back(id);
}
public:
// Constructor
Player(int pID, int sMoney) {
this->playerID = pID;
this->money = sMoney;
}
// Functions
Player payMoney(int payAmount, unsigned int destinationID, Game engine) {
this->money -= payAmount;
if (destinationID > 0) {
// Checks if you're paying to a player or bank
bool playerFound = false;
for (int i = 0; i <= engine.getPlayerAmount(); ++i) {
if (engine.getPlayer(i).getID() == destinationID) {
playerFound = true;
break;
}
}
if (playerFound) {
// Player was found
engine.getPlayer(destinationID).giveMoney(payAmount);
return;
}
else {
std::cout << "\nERROR: Invalid player ID at function payMoney\n";
return;
}
}
else {
// You're paying to the bank
}
return;
}
void buyProperty(int id, int price, Game engine) {
payMoney(price, 0, engine);
addProperty(id);
}
void giveMoney(int payMoney) {
this->money += payMoney;
}
// Returns
inline int getMoney() { return this->money; }
inline int getID() { return this->playerID; }
inline auto getProperties(int index) {
auto p = propertiesOwned[index];
return p;
}
inline int getPropertyAmount() {
int amount = std::size(propertiesOwned);
return amount;
}
};
}
I expected the classes to run the other classes function normally, but it seens like that in C++, classes are defined in certain order, and you can only access classes (in a class) declared before the class you're using, feedback and alternatives that fix this would help
You are correct that in C++ declaration order matters, and that is the cause of your errors, however there are a few other issues with the code.
Firstly, you should swap the order that Game and Player are defined. This will make it easier, as Player relies on Game fewer times than Game relies on Player.
Next, add a forward declaration for Game before the definition of Player:
class Game;
This tells the compiler that a class named Game exists and allows you to use it in scenarios where it doesn't need to know the contents (i.e. definition) of the class.
Next, make payMoney and buyProperty accept their engine parameter by reference instead of by value by changing the parameter specifier to Game &engine. This is important for two reasons. First, passing by value can only be done if you have already defined the type, which we have not (we've only declared it). Second, passing by value creates a copy of the object, which in this case means a completely new vector of completely new Player objects, and the changes will not synchronize back to the old object. See here for a better explanation of references.
Next, you need to extract the definition of payMoney to after the definition of Game. The reason is that while the parameter list of payMoney no longer relies on the definition of Game, the code in the function body does (because it calls functions on the engine object). See the end for what this looks like.
This fixes all the problems with declaration/definition order. You also should make payMoney return void as its return value is never provided and never used, pick a consistent type for IDs (either int or unsigned int, not a mix), and add the getPlayerAmount to Game.
Here's what the final code could look like:
namespace Monopoly {
typedef enum { normal, train, company, incometax, luxurytax, start, chancecard, chestcard, jail } type;
class Game;
class Player {
private:
int playerID;
int money;
std::vector<int> propertiesOwned;
void addProperty(int id) {
this->propertiesOwned.push_back(id);
}
public:
// Constructor
Player(int pID, int sMoney) {
this->playerID = pID;
this->money = sMoney;
}
// Functions
void payMoney(int payAmount, int destinationID, Game &engine);
void buyProperty(int id, int price, Game &engine) {
payMoney(price, 0, engine);
addProperty(id);
}
void giveMoney(int payMoney) {
this->money += payMoney;
}
// Returns
inline int getMoney() { return this->money; }
inline int getID() { return this->playerID; }
inline auto getProperties(int index) {
auto p = propertiesOwned[index];
return p;
}
inline int getPropertyAmount() {
int amount = std::size(propertiesOwned);
return amount;
}
};
class Game {
private:
bool running = false;
int turn = 1;
int currentPlayerID;
int startingMoney = 1000;
std::vector<Player> players;
public:
// Functions
void createPlayer() {
++currentPlayerID;
Player newPlayer(currentPlayerID, startingMoney);
players.push_back(newPlayer);
++currentPlayerID;
}
void createPlayers(int playerAmount) {
for (int i = 0; i <= playerAmount; ++i) {
createPlayer();
}
}
Player getPlayer(int index) {
Player p = players[index];
return p;
}
int getPlayerAmount() {
int amount = players.size();
return amount;
}
};
void Player::payMoney(int payAmount, int destinationID, Game &engine) {
this->money -= payAmount;
if (destinationID > 0) {
// Checks if you're paying to a player or bank
bool playerFound = false;
for (int i = 0; i <= engine.getPlayerAmount(); ++i) {
if (engine.getPlayer(i).getID() == destinationID) {
playerFound = true;
break;
}
}
if (playerFound) {
// Player was found
engine.getPlayer(destinationID).giveMoney(payAmount);
return;
}
else {
std::cout << "\nERROR: Invalid player ID at function payMoney\n";
return;
}
}
else {
// You're paying to the bank
}
return;
}
}
Side note: it's technically better C++ to use size_t instead of int for variables storing the size of vectors, as that is what the size functions return (and it's an unsigned integer type whereas int is signed), but that's not especially important.
According to the topic Pushing local objects into a list
The full class:
class Invader
{
public:
Invader(const Invader&other);
Invader();
~Invader();
public:
void Init(InvaderTypes invadertype, CIw2DImage *AlienImage);
void Update(float dt);
void Render();
void SetAlienImage(CIw2DImage *image){ mImageAlien = image; }
void setVisible(bool show) { Visible = show; }
bool isVisible() const { return Visible; }
Iw2DSceneGraph::CSprite *AlienSprite;
Iw2DSceneGraph::CAtlas *AlienAtals;
CIw2DImage *mImageAlien;
std::list<Bullet*> *Bullets;
CIwFMat2D Transform; // Transform matrix
bool Visible; // Sprites visible state
bool Canfire;
};
Invader::Invader()
{
}
Invader::Invader(const Invader&other)
{ // Create EnemyTop atlas
AlienAtals = new CAtlas();
AlienSprite = new CSprite();
*AlienAtals = *other.AlienAtals;
*AlienSprite = *other.AlienSprite;
}
Invader::~Invader()
{
for (std::list<Bullet*>::iterator it = Bullets->begin(); it != Bullets->end(); ++it)
delete *it;
delete Bullets;
delete AlienAtals;
delete AlienSprite;
}
void Invader::Init(InvaderTypes invadertype, CIw2DImage *AlienImage)
{
if (invadertype == InvaderTypes::TOP_ALIEN)
{
//SetAlienImage(AlienImage);
mImageAlien = AlienImage;
// Create EnemyTop atlas
int frame_w = (int)(mImageAlien->GetWidth() / 2);
int frame_h = (int)(mImageAlien->GetHeight());
AlienAtals = new CAtlas(frame_w, frame_h, 2, mImageAlien);
AlienSprite = new CSprite();
AlienSprite->m_X = 0;
AlienSprite->m_Y = 0;
AlienSprite->SetAtlas(AlienAtals);
AlienSprite->m_W = (float)AlienAtals->GetFrameWidth();
AlienSprite->m_H = (float)AlienAtals->GetFrameHeight();
AlienSprite->m_AnchorX = 0.5;
AlienSprite->SetAnimDuration(2);
}
else if (invadertype == InvaderTypes::MIDDLE_ALIEN)
{
}
else if (invadertype == InvaderTypes::LAST_ALIEN)
{
}
Visible = true;
Bullets = new std::list<Bullet*>();
Canfire = true;
}
I added the objects by doing:
list<Invader> invaders;
int spacing = 10;
for (int i = 0; i < 5; i++)
{
Invader invader;
invader.Init(TOP_ALIEN, gameResources->getAlienImageTop());
invader.AlienSprite->m_X = 50 + spacing;
invaders.push_back(invader);
spacing += 50;
}
the usage: Right now it causes an access violation when accessing (it)
for (list<Invader>::iterator it = invaders.begin(); it != invaders.end(); it++)
{
(it)->Update(FRAME_TIME);
(it)->Render();
}
You can see the result here in the following image:
First, during Invader::Init()), you provide a copy of the pointer to AlienImage. Then when you copy the object into the std::list, you don't copy that same pointer to the new object. Further, during Invader::Invader(const Invader& other), you are not making a copy of Invader::Bullets. This leaves both the values uninitialized causing Undefined Behavior upon access (which probably occurs in (it)->Update(FRAME_TYIME); and/or (it)->Render(); -- I can't verify since you didn't provide a MCVE.
I've got two classes namely Family.cpp and Child.cpp. Using the instance of family I can only add a youngest child (i.e., at the end). And using the Child class I can create only an immediate younger child. This could be done by obtaining the child from the family class function Child* getChild(unsigned int i).
Family.h
#ifndef FAMILY_H_
#define FAMILY_H_
#include "Child.h"
// This is a more advanced exercise for copy and move
// constructors.
// Here there is a system of two classes and the
// copy and move should apply to the Family so as
// to create a full copy of the Family and Child.
// You can think about the main thing that is used
// by other users as the Family and the Child is
// exposed but it is going to be used only as part
// of a Family.
//
// The Family contains several children.
// The main functions that are possible to do
// to a family is to add a (youngest) child
// and to retrieve the i-th child.
// A family also supports copy and move semantics.
class Family {
public:
Family();
Family(const Family&);
~Family();
// Add a new youngest child with this name and this
// dob.
void addChild(const char* name, unsigned int dob);
// Get the i-th child of the family
Child* getChild(unsigned int) const;
// Copy and move through assignment operator
Family& operator=(const Family&);
Family& operator=(Family&&);
private:
void inline addChildren_(const Family&);
void inline reallocate_();
void inline clean_();
Child** children_;
unsigned int childrenCapacity_;
unsigned int numberOfChildren_;
};
#endif /* FAMILY_H_ */
Child.h
#ifndef CHILD_H_
#define CHILD_H_
// This is the child that should appear as part of the family.
// Each child has a name and a date of birth
// The length of the name should be unbounded
// Each child also has pointers to the (closest) older sibling and
// the (closest) younger sibling.
// If there is no such sibling, then, clearly, this pointer is nullptr.
// Each child
class Child {
public:
Child();
Child(const char* name,unsigned int dob);
~Child();
void name(char* buffer) const;
unsigned int dob() const;
Child* olderSibling() const;
Child* youngerSibling() const;
// Create a new immediate younger sibling (using dynamic memory!!!)
// If a younger sibling already exists then the new one is adopted
// and should be between the two.
// If the age order between the siblings turns out to be
// wrong the operation should fail and return null pointer.
// Notice that twins (yes, up to the millisecond) should be
// possible.
Child* addYoungerSibling(const char* name, unsigned int dob);
// Copy and move through assignment operators
Child& operator=(const Child& other);
Child& operator=(Child&&);
private:
Child* siblingOlder_;
Child* siblingYounger_;
char* childName_;
int childDob_;
void inline copyChildName_(const Child&);
void clean_();
};
#endif /* CHILD_H_ */
Family.cpp
#include "Family.h"
Family::Family() :
children_(nullptr), childrenCapacity_(0), numberOfChildren_(0) {
}
Family::~Family() {
clean_();
}
void Family::addChild(const char* name, unsigned int dob) {
if ((numberOfChildren_ > 0)
&& (children_[numberOfChildren_ - 1]->dob() >= dob)) {
return;
}
if (numberOfChildren_ == childrenCapacity_) {
reallocate_();
}
if (numberOfChildren_ == 0) {
children_[numberOfChildren_] = new Child(name, dob);
} else {
children_[numberOfChildren_] =
children_[numberOfChildren_ - 1]->addYoungerSibling(name, dob);
}
++numberOfChildren_;
}
Child* Family::getChild(unsigned int i) const {
if (i < numberOfChildren_) {
return children_[i];
}
return nullptr;
}
void Family::reallocate_() {
Child** tempChildren = new Child*[childrenCapacity_ + 5];
for (unsigned int i = 0; i < childrenCapacity_ + 5; i++) {
tempChildren[i] = (i < childrenCapacity_ ? children_[i] : nullptr);
}
if (children_) {
delete[] children_;
}
children_ = tempChildren;
childrenCapacity_ += 5;
}
Child.cpp
#include <string.h>
#include "Child.h"
Child::Child() :
siblingOlder_(nullptr), siblingYounger_(nullptr), childName_(nullptr), childDob_(
0) {
}
Child::Child(const char* name, unsigned int dob) :
siblingOlder_(nullptr), siblingYounger_(nullptr), childName_(
new char[strlen(name) + 1]), childDob_(dob) {
unsigned int i = 0;
for (; name[i]; i++) {
childName_[i] = name[i];
}
childName_[i] = 0;
}
Child::~Child() {
clean_();
}
void Child::name(char* buffer) const {
strcpy(buffer, childName_);
}
unsigned int Child::dob() const {
return childDob_;
}
Child* Child::olderSibling() const {
return siblingOlder_;
}
Child* Child::youngerSibling() const {
return siblingYounger_;
}
Child* Child::addYoungerSibling(const char* name, unsigned int dob) {
if ((!siblingYounger_) && (childDob_ < dob)) {
Child *temp = new Child(name, dob);
siblingYounger_ = temp;
temp->siblingOlder_ = this;
return temp;
} else if (siblingYounger_) {
int youngerDob = youngerSibling()->dob();
if (dob > childDob_ && dob < youngerDob) {
Child *temp = new Child(name, dob);
temp->siblingYounger_ = siblingYounger_;
temp->siblingOlder_ = this;
siblingYounger_->siblingOlder_ = temp;
siblingYounger_ = temp;
return temp;
}
}
return nullptr;
}
void Child::copyChildName_(const Child& other) {
unsigned int i = 0;
for (; other.childName_[i]; i++) {
childName_[i] = other.childName_[i];
}
childName_[i];
}
Problem:
I had the following code in main.cpp and I got the output as below which was acceptable.
Family f;
f.addChild("A", 5);
f.addChild("B", 10);
f.addChild("D", 20);
printFamily(f);
Output:
Members: A 5, B 10, D 20,
A is older than B
B is younger than A and is older than D
D is younger than B
But when I had the following code appended to main.cpp, the output was as below.
Child *childB = f.getChild(1);
Child *childC = childB->addYoungerSibling("C", 15);
printFamily(f);
Output:
Members: A 5, B 10, D 20,
A is older than B
B is younger than A and is older than C
D is younger than C
I think when I try to add a younger child, it gets added but not loaded in the family memory. How do I solve this issue?
maybe you didn't add him to the family?
not added to children_[]?
You should probably call addChild it calls addYoungerSibling...
also your in c++, use strings not chars (why strcpy when you can just return a string?)
there are all sort of things you can fix in you code. if you upload the h files it will be easier to help, if you like.
good luck
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I'm totally at wit's end: I can't figure out how my dependency issues. I've read countless posts and blogs and reworked my code so many times that I can't even remember what almost worked and what didnt. I continually get not only redefinition errors, but class not defined errors. I rework the header guards and remove some errors simply to find others. I somehow got everything down to one error but then even that got broke while trying to fix it.
Would you please help me figure out the problem?
card.cpp
#include <iostream>
#include <cctype>
#include "card.h"
using namespace std;
// ====DECL======
Card::Card()
{
abilities = 0;
flavorText = 0;
keywords = 0;
artifact = 0;
classType = new char[strlen("Card") + 1];
classType = "Card";
}
Card::~Card (){
delete name;
delete abilities;
delete flavorText;
artifact = NULL;
}
// ------------
Card::Card(const Card & to_copy)
{
name = new char[strlen(to_copy.name) +1]; // creating dynamic array
strcpy(to_copy.name, name);
type = to_copy.type;
color = to_copy.color;
manaCost = to_copy.manaCost;
abilities = new char[strlen(to_copy.abilities) +1];
strcpy(abilities, to_copy.abilities);
flavorText = new char[strlen(to_copy.flavorText) +1];
strcpy(flavorText, to_copy.flavorText);
keywords = new char[strlen(to_copy.keywords) +1];
strcpy(keywords, to_copy.keywords);
inPlay = to_copy.inPlay;
tapped = to_copy.tapped;
enchanted = to_copy.enchanted;
cursed = to_copy.cursed;
if (to_copy.type != ARTIFACT)
artifact = to_copy.artifact;
}
// ====DECL=====
int Card::equipArtifact(Artifact* to_equip){
artifact = to_equip;
}
Artifact * Card::unequipArtifact(Card * unequip_from){
Artifact * to_remove = artifact;
artifact = NULL;
return to_remove;
// put card in hand or in graveyard
}
int Card::enchant( Card * to_enchant){
to_enchant->enchanted = true;
cout << "enchanted" << endl;
}
int Card::disenchant( Card * to_disenchant){
to_disenchant->enchanted = false;
cout << "Enchantment Removed" << endl;
}
// ========DECL=====
Spell::Spell()
{
currPower = basePower;
currToughness = baseToughness;
classType = new char[strlen("Spell") + 1];
classType = "Spell";
}
Spell::~Spell(){}
// ---------------
Spell::Spell(const Spell & to_copy){
currPower = to_copy.currPower;
basePower = to_copy.basePower;
currToughness = to_copy.currToughness;
baseToughness = to_copy.baseToughness;
}
// =========
int Spell::attack( Spell *& blocker ){
blocker->currToughness -= currPower;
currToughness -= blocker->currToughness;
}
//==========
int Spell::counter (Spell *& to_counter){
cout << to_counter->name << " was countered by " << name << endl;
}
// ============
int Spell::heal (Spell *& to_heal, int amountOfHealth){
to_heal->currToughness += amountOfHealth;
}
// -------
Creature::Creature(){
summoningSick = true;
}
// =====DECL======
Land::Land(){
color = NON;
classType = new char[strlen("Land") + 1];
classType = "Land";
}
// ------
int Land::generateMana(int mana){
// ... //
}
card.h
#ifndef CARD_H
#define CARD_H
#include <cctype>
#include <iostream>
#include "conception.h"
class Artifact;
class Spell;
class Card : public Conception
{
public:
Card();
Card(const Card &);
~Card();
protected:
char* name;
enum CardType { INSTANT, CREATURE, LAND, ENCHANTMENT, ARTIFACT, PLANESWALKER};
enum CardColor { WHITE, BLUE, BLACK, RED, GREEN, NON };
CardType type;
CardColor color;
int manaCost;
char* abilities;
char* flavorText;
char* keywords;
bool inPlay;
bool tapped;
bool cursed;
bool enchanted;
Artifact* artifact;
virtual int enchant( Card * );
virtual int disenchant (Card * );
virtual int equipArtifact( Artifact* );
virtual Artifact* unequipArtifact(Card * );
};
// ------------
class Spell: public Card
{
public:
Spell();
~Spell();
Spell(const Spell &);
protected:
virtual int heal( Spell *&, int );
virtual int attack( Spell *& );
virtual int counter( Spell*& );
int currToughness;
int baseToughness;
int currPower;
int basePower;
};
class Land: public Card
{
public:
Land();
~Land();
protected:
virtual int generateMana(int);
};
class Forest: public Land
{
public:
Forest();
~Forest();
protected:
int generateMana();
};
class Creature: public Spell
{
public:
Creature();
~Creature();
protected:
bool summoningSick;
};
class Sorcery: public Spell
{
public:
Sorcery();
~Sorcery();
protected:
};
#endif
conception.h -- this is an "uber class" from which everything derives
class Conception{
public:
Conception();
~Conception();
protected:
char* classType;
};
conception.cpp
Conception::Conception{
Conception(){
classType = new char[11];
char = "Conception";
}
game.cpp -- this is an incomplete class as of this code
#include <iostream>
#include <cctype>
#include "game.h"
#include "player.h"
Battlefield::Battlefield(){
card = 0;
}
Battlefield::~Battlefield(){
delete card;
}
Battlefield::Battlefield(const Battlefield & to_copy){
}
// ===========
/*
class Game(){
public:
Game();
~Game();
protected:
Player** player; // for multiple players
Battlefield* root; // for battlefield
getPlayerMove(); // ask player what to do
addToBattlefield();
removeFromBattlefield();
sendAttack();
}
*/
#endif
game.h
#ifndef GAME_H
#define GAME_H
#include "list.h"
class CardList();
class Battlefield : CardList{
public:
Battlefield();
~Battlefield();
protected:
Card* card; // make an array
};
class Game : Conception{
public:
Game();
~Game();
protected:
Player** player; // for multiple players
Battlefield* root; // for battlefield
getPlayerMove(); // ask player what to do
addToBattlefield();
removeFromBattlefield();
sendAttack();
Battlefield* field;
};
list.cpp
#include <iostream>
#include <cctype>
#include "list.h"
// ==========
LinkedList::LinkedList(){
root = new Node;
classType = new char[strlen("LinkedList") + 1];
classType = "LinkedList";
};
LinkedList::~LinkedList(){
delete root;
}
LinkedList::LinkedList(const LinkedList & obj)
{
// code to copy
}
// ---------
// =========
int LinkedList::delete_all(Node* root){
if (root = 0)
return 0;
delete_all(root->next);
root = 0;
}
int LinkedList::add( Conception*& is){
if (root == 0){
root = new Node;
root->next = 0;
}
else
{
Node * curr = root;
root = new Node;
root->next=curr;
root->it = is;
}
}
int LinkedList::remove(Node * root, Node * prev, Conception* is){
if (root = 0)
return -1;
if (root->it == is){
root->next = root->next;
return 0;
}
remove(root->next, root, is);
return 0;
}
Conception* LinkedList::find(Node*& root, const Conception* is, Conception* holder = NULL)
{
if (root==0)
return NULL;
if (root->it == is){
return root-> it;
}
holder = find(root->next, is);
return holder;
}
Node* LinkedList::goForward(Node * root){
if (root==0)
return root;
if (root->next == 0)
return root;
else
return root->next;
}
// ============
Node* LinkedList::goBackward(Node * root){
root = root->prev;
}
list.h
#ifndef LIST_H
#define LIST_H
#include <iostream>
#include "conception.h"
class Node : public Conception {
public:
Node() : next(0), prev(0), it(0)
{ it = 0;
classType = new char[strlen("Node") + 1];
classType = "Node";
};
~Node(){
delete it;
delete next;
delete prev;
}
Node* next;
Node* prev;
Conception* it; // generic object
};
// ----------------------
class LinkedList : public Conception {
public:
LinkedList();
~LinkedList();
LinkedList(const LinkedList&);
friend bool operator== (Conception& thing_1, Conception& thing_2 );
protected:
virtual int delete_all(Node*);
virtual int add( Conception*& ); //
virtual Conception* find(Node *&, const Conception*, Conception* ); //
virtual int remove( Node *, Node *, Conception* ); // removes question with keyword int display_all(node*& );
virtual Node* goForward(Node *);
virtual Node* goBackward(Node *);
Node* root;
// write copy constrcutor
};
// =============
class CircularLinkedList : public LinkedList {
public:
// CircularLinkedList();
// ~CircularLinkedList();
// CircularLinkedList(const CircularLinkedList &);
};
class DoubleLinkedList : public LinkedList {
public:
// DoubleLinkedList();
// ~DoubleLinkedList();
// DoubleLinkedList(const DoubleLinkedList &);
protected:
};
// END OF LIST Hierarchy
#endif
player.cpp
#include <iostream>
#include "player.h"
#include "list.h"
using namespace std;
Library::Library(){
root = 0;
}
Library::~Library(){
delete card;
}
// ====DECL=========
Player::~Player(){
delete fname;
delete lname;
delete deck;
}
Wizard::~Wizard(){
delete mana;
delete rootL;
delete rootH;
}
// =====Player======
void Player::changeName(const char[] first, const char[] last){
char* backup1 = new char[strlen(fname) + 1];
strcpy(backup1, fname);
char* backup2 = new char[strlen(lname) + 1];
strcpy(backup1, lname);
if (first != NULL){
fname = new char[strlen(first) +1];
strcpy(fname, first);
}
if (last != NULL){
lname = new char[strlen(last) +1];
strcpy(lname, last);
}
return 0;
}
// ==========
void Player::seeStats(Stats*& to_put){
to_put->wins = stats->wins;
to_put->losses = stats->losses;
to_put->winRatio = stats->winRatio;
}
// ----------
void Player::displayDeck(const LinkedList* deck){
}
// ================
void CardList::findCard(Node* root, int id, NodeCard*& is){
if (root == NULL)
return;
if (root->it.id == id){
copyCard(root->it, is);
return;
}
else
findCard(root->next, id, is);
}
// --------
void CardList::deleteAll(Node* root){
if (root == NULL)
return;
deleteAll(root->next);
root->next = NULL;
}
// ---------
void CardList::removeCard(Node* root, int id){
if (root == NULL)
return;
if (root->id = id){
root->prev->next = root->next; // the prev link of root, looks back to next of prev node, and sets to where root next is pointing
}
return;
}
// ---------
void CardList::addCard(Card* to_add){
if (!root){
root = new Node;
root->next = NULL;
root->prev = NULL;
root->it = &to_add;
return;
}
else
{
Node* original = root;
root = new Node;
root->next = original;
root->prev = NULL;
original->prev = root;
}
}
// -----------
void CardList::displayAll(Node*& root){
if (root == NULL)
return;
cout << "Card Name: " << root->it.cardName;
cout << " || Type: " << root->it.type << endl;
cout << " --------------- " << endl;
if (root->classType == "Spell"){
cout << "Base Power: " << root->it.basePower;
cout << " || Current Power: " << root->it.currPower << endl;
cout << "Base Toughness: " << root->it.baseToughness;
cout << " || Current Toughness: " << root->it.currToughness << endl;
}
cout << "Card Type: " << root->it.currPower;
cout << " || Card Color: " << root->it.color << endl;
cout << "Mana Cost" << root->it.manaCost << endl;
cout << "Keywords: " << root->it.keywords << endl;
cout << "Flavor Text: " << root->it.flavorText << endl;
cout << " ----- Class Type: " << root->it.classType << " || ID: " << root->it.id << " ----- " << endl;
cout << " ******************************************" << endl;
cout << endl;
// -------
void CardList::copyCard(const Card& to_get, Card& put_to){
put_to.type = to_get.type;
put_to.color = to_get.color;
put_to.manaCost = to_get.manaCost;
put_to.inPlay = to_get.inPlay;
put_to.tapped = to_get.tapped;
put_to.class = to_get.class;
put_to.id = to_get.id;
put_to.enchanted = to_get.enchanted;
put_to.artifact = to_get.artifact;
put_to.class = to_get.class;
put.to.abilities = new char[strlen(to_get.abilities) +1];
strcpy(put_to.abilities, to_get.abilities);
put.to.keywords = new char[strlen(to_get.keywords) +1];
strcpy(put_to.keywords, to_get.keywords);
put.to.flavorText = new char[strlen(to_get.flavorText) +1];
strcpy(put_to.flavorText, to_get.flavorText);
if (to_get.class = "Spell"){
put_to.baseToughness = to_get.baseToughness;
put_to.basePower = to_get.basePower;
put_to.currToughness = to_get.currToughness;
put_to.currPower = to_get.currPower;
}
}
// ----------
player.h
#ifndef player.h
#define player.h
#include "list.h"
// ============
class CardList() : public LinkedList(){
public:
CardList();
~CardList();
protected:
virtual void findCard(Card&);
virtual void addCard(Card* );
virtual void removeCard(Node* root, int id);
virtual void deleteAll();
virtual void displayAll();
virtual void copyCard(const Conception*, Node*&);
Node* root;
}
// ---------
class Library() : public CardList(){
public:
Library();
~Library();
protected:
Card* card;
int numCards;
findCard(Card&); // get Card and fill empty template
}
// -----------
class Deck() : public CardList(){
public:
Deck();
~Deck();
protected:
enum deckColor { WHITE, BLUE, BLACK, RED, GREEN, MIXED };
char* deckName;
}
// ===============
class Mana(int amount) : public Conception {
public:
Mana() : displayTotal(0), classType(0)
{ displayTotal = 0;
classType = new char[strlen("Mana") + 1];
classType = "Mana";
};
protected:
int accrued;
void add();
void remove();
int displayTotal();
}
inline Mana::add(){ accrued += 1; }
inline Mana::remove(){ accrued -= 1; }
inline Mana::displayTotal(){ return accrued; }
// ================
class Stats() : public Conception {
public:
friend class Player;
friend class Game;
Stats() : wins(0), losses(0), winRatio(0) {
wins = 0; losses = 0;
if ( (wins + losses != 0)
winRatio = wins / (wins + losses);
else
winRatio = 0;
classType = new char[strlen("Stats") + 1];
classType = "Stats";
}
protected:
int wins;
int losses;
float winRatio;
void int getStats(Stats*& );
}
// ==================
class Player() : public Conception{
public:
Player() : wins(0), losses(0), winRatio(0) {
fname = NULL;
lname = NULL;
stats = NULL;
CardList = NULL;
classType = new char[strlen("Player") + 1];
classType = "Player";
};
~Player();
Player(const Player & obj);
protected:
// member variables
char* fname;
char* lname;
Stats stats; // holds previous game statistics
CardList* deck[]; // hold multiple decks that player might use - put ll in this
private:
// member functions
void changeName(const char[], const char[]);
void shuffleDeck(int);
void seeStats(Stats*& );
void displayDeck(int);
chooseDeck();
}
// --------------------
class Wizard(Card) : public Player(){
public:
Wizard() : { mana = NULL; rootL = NULL; rootH = NULL};
~Wizard();
protected:
playCard(const Card &);
removeCard(Card &);
attackWithCard(Card &);
enchantWithCard(Card &);
disenchantWithCard(Card &);
healWithCard(Card &);
equipWithCard(Card &);
Mana* mana[];
Library* rootL; // Library
Library* rootH; // Hand
}
#endif
At least one of your problems is that in "player.h" you have
#ifndef player.h
#define player.h
"player.h" is not a legal pre-processor symbol. Did you mean
#ifndef player_h
#define player_h
?
Secondly, conception.cpp doesn't #include anything.
Third, your class definitions are largely invalid.
class Foo()
is not legal, nor is
class Foo() : public class Bar()
What does '()' have to do with a class name? Are you thinking of the constructor?
Then there is this
char = "Conception";
You can't assign a value to a type.
----- Feedback to help you clean up the code -----
. Choose a style
Or - if you are working with someone else's code, take theirs.
But stick with it.
A huge percentage of software defects that make it past initial development are there because they were hard to spot - missing semi-colons, missing {s around compound statements, etc. C.f. "CARD_H" vs "player.h".
. Inconsistency is the mother of most bugs
classType = new char[11];
char = "Conception";
You probably mean
classType = new char[11];
classType = "Conception";
but this is a memory leak and a bug waiting to happen. In Card:: you do it more correctly
name = new char[strlen(to_copy.name) +1]; // creating dynamic array
strcpy(to_copy.name, name);
The version you use elsewhere
classType = new ...
classType = "String";
allocates some memory, stores the address in classType. Then it looks up the variable of the compiled char* array "String\0" and stores it's address in classType instead.
When the class goes away, it will try to delete the static string and crash.
If this is a learning exercise and you're trying to learn about memory management, this general approach may be fair enough. But placing ownership of pointers in your classes like this is a sure-fire way to wind up with memory leaks and undefined behavior bugs.
It's best to encapsulate pointers in an RAII-style class (a class which owns the pointer and does the delete when it goes out of scope). Take a look into "std::unique_ptr", "std::shared_ptr" and "std::weak_ptr". For your purposes, "std::string" may help you reduce the number of defects by eliminating a lot of the managerial overhead.
. Try to avoid mixing initializer lists with assignment lists.
It's generally better to use one or the other. You can probably get away with using initializer lists when all of your members can be initialized that way, but if they can't, it may be better to use assignment.
Foo() : m_a(), m_b(), m_c() { m_b = 1; m_c = 2; } // is m_a not having a value a bug or intentional?
. Distinguish member variables from ordinary variables.
You're going to run into bugs where values dissapear on you as a result of shadowing: Shadowing variables
#include <iostream>
int i = 0;
int main() {
int i = 1;
for (int i = 0; i < 10; ++i) {
int i = 2 * i;
std::cout << i << std::endl;
}
return 0;
}
when you don't distinguish your member variables (a lot of people use an "m_" prefix, others use a "_" suffix) this is GOING to happen to you frequently.
. Don't assign numeric values to pointers.
name = 0;
while this compiles, you're setting yourself up for less obvious cases appearing to be numbers and Bad Things Ensuing.
abilities = 0;
No, I'm superman, I have ALL the abilities.
abilities = 42;
Two more correct ways to do this would be
name = NULL; // Traditional C++
or
name = nullptr; // C++11
You've done this in someplaces, again consistency is failing you.
. (minor but it'll bite you in the ass in a few weeks) "it" is generally used to reference an "iterator", you might want to use "data" or "value" or "element".
. avoid making members of classes/objects public.
Your "Node" class looks incredibly buggy (the destructor deletes both prev and next???) and you can't tell, from looking at the class, how the "it" pointer gets set, presumably because that happens elsewhere. Where else do you tamper with the "it", prev and next pointers? Encapsulate.
. 'const' can be your friend (by being a pain in your ass)
if (to_get.class = "Spell"){
This will assign "Spell" to to_get.class, causing a memory leak and other issues, and then succeed -- "Spell" evaluates to a fixed const char* address, which is non-zero, which is therefore true.
(It also doesn't compile because 'class' is a keyword and the actual variable is 'className').
You can prevent this by protecting your actual members and only exposing them thru carefully chosen accessors.
const char* Class() const { return m_className; }
Let me break this one down:
const char* :- you cannot modify the contents,
Class() :- instead of to_get.class you'll use to_get.Class()
const :- this function does not have side-effects on the object
The last part means that it can be used on a const object.
class Beer {
bool m_isFull;
public:
Beer() : m_isFull(true) {}
// non-const function, has side-effects (changes isFull);
void drink() { m_isFull = false; }
// const function, returns a copy of "m_isFull". you can
// change the value that's returned, but it doesn't affect us.
void isFull() const { return m_isFull; }
// example of a non-const accessor, if you REALLY want
// the caller to be able to modify m_isFull for some reason.
const bool& getIsFull() { return m_isFull; }
};
. Lastly: Learn to isolate concepts and algorithms.
A lot of the mistakes/bugs/errors in the code appear to be because you're not 100% with some of the nuances or even details. That's not unreasonable, but you need to find a way to be able to try out the little bits of the language.
Take a little time to learn to roll out micro-programs on something like ideone.com. If you are using Linux, make yourself a "srctest" directory with a "test.cpp" and "test.h" and a Makefile
Makefile
all: srctest
srctest: srctest.cpp srctestextern.cpp srctest.h
g++ -o srctest -Wall -ggdb srctest.cpp srctestextern.cpp
srctest.cpp
#include "srctest.h"
#include <iostream>
// add your other includes here and just leave them.
int main() {
return 0;
}
srctest.h
#ifndef SRCTEST_SRCTEST_H
#define SRCTEST_SRCTEST_H
// anything I want to test in a .h file here
#endif
srctestextern.cpp
#include "srctest.h"
// Anything you want to test having in a separate source file goes here.
If you're using visual studio, set yourself up something similar.
The idea is to have somewhere you can go and drop in a few lines of code and be comfortable stepping thru what you're trying in a debugger.
Being able to quickly localize problems is a key part of being a successful programmer as opposed to being an employed code monkey.
I have those inheritance classes :
Base Class: Entity
Derived from Entity Classes: Actor, Obj, Enemy
The Base class Entity contains an obj of a user-defined-type that i called "CollisionStuff".
When i run my program the destructor of CollisionStuff is called after every CollisionStuff constructor call and every time game-loop goes on.
so my call is: why is this happening?
As you can see below, i allocate dinamically some arrays in the setRectangle method, the programm calls the destructor, it deletes my data and when i try to use them... it calls "_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));".
Thank you in before
here my code: Entity.h
enum e_Type {tActor = 0, tObj, tEnemy, tBackg};
class Entity
{
public:
Entity(void);
~Entity(void);
float getH();
float getW();
void setWH(float W, float H);
bool CreateSprite(std::string path);
sf::Sprite& getSprite();
void setType(e_Type type);
e_Type getType();
CollisionStuff getColStuff();
static std::list<Entity*> List;
protected:
sf::Sprite m_sprite;
sf::Texture m_texture;
float m_h;
float m_w;
e_Type m_type;
CollisionStuff m_colStuff;
void addToList();
};
CollisionStuff.h
class CollisionStuff
{
public:
CollisionStuff();
~CollisionStuff(void);
void setRectangle(int W, int H);
void followTheSprite(Entity entity);
private:
sf::Vector2f* m_a;
sf::Vector2f* m_b;
sf::Vector2f* m_c;
sf::Vector2f* m_d;
/* this member data are sides of rectangle used
to manage collisions between object throughout the scenario
a
-------------
| |
c | | d
| |
-------------
b
*/
};
CollisionStuff.cpp
CollisionStuff::CollisionStuff()
{
//setRectangle(0, 0);
}
void CollisionStuff::setRectangle(int W, int H)
{
m_a = new sf::Vector2f[W];
m_b = new sf::Vector2f[W];
m_c = new sf::Vector2f[H];
m_d = new sf::Vector2f[H];
}
void CollisionStuff::followTheSprite(Entity entity)
{
entity.getSprite().setOrigin(0, 0);
sf::Vector2f UpLeftVertex = entity.getSprite().getPosition();
for(int i = 0; i < entity.getW(); i++)
{
m_a[i].x = UpLeftVertex.x + i;
m_a[i].y = UpLeftVertex.y;
m_b[i].x = UpLeftVertex.x + i;
m_b[i].y = UpLeftVertex.y + entity.getH();
}
for(int i = 0; i < entity.getH(); i++)
{
m_c[i].x = UpLeftVertex.x;
m_c[i].y = UpLeftVertex.y + i;
m_d[i].x = UpLeftVertex.x + entity.getW();
m_d[i].y = UpLeftVertex.y + i;
}
}
CollisionStuff::~CollisionStuff(void)
{
delete [] m_a;
delete [] m_b;
delete [] m_c;
delete [] m_d;
}
EDIT
Thank you for the answers.
Example of CollisionStuff use
Actor.cpp (it's a derived class of Entity)
Actor::Actor(void)
{
if(!CreateSprite("D://Sprites//MainChar.png"))
{
std::cout << "Impossibile creare sprite" << std::endl;
}
else
{
std::cout << "Creazione sprite riuscita" << std::endl;
m_sprite.setPosition(100.0f, 365.0f);
m_sprite.setOrigin(20, 35);
//m_sprite.setPosition(190.0f, 382.5f); // 200, 400
setWH(40, 70);
m_health = 100;
m_status = Good;
setType(tActor);
m_jCounter = -1;
m_action = Null;
setColStuff();
}
}
void Actor::setColStuff()
{
m_colStuff.setRectangle(m_w, m_h);
}
void Actor::physic()
{
//setColStuff();
m_colStuff.followTheSprite(*this);
}
main.cpp
int main()
{
sf::RenderWindow window(sf::VideoMode(800, 600), "Platform");
std::list<Entity*>::iterator i;
Background BG;
Level1 FirstLev;
Actor Doodle;
while(window.isOpen())
{
sf::Event event;
if(window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
Doodle.inputEvts();
}
Doodle.act(Doodle.getAction());
Doodle.physic();
window.clear();
window.draw(BG.getSprite());
window.draw(Doodle.getSprite());
FirstLev.drawLevel(window);
window.display();
}
return 0;
}
It's really hard to tell from the bit of code that you posted, but if I had to guess I'd say it's probably related to this:
CollisionStuff getColStuff();
you're returning CollisionStuff by value, which means a new copy will be created by whoever is calling this. It'll have the same pointers that the original CollisionStuff object allocated, and it'll delete them when it goes out of scope, leaving the original one with dangling pointers.
You can try returning by reference or by pointer, but either way you should write a copy constructor and override the assignment operator for CollisionStuff (Rule of Three).
Another idea would be to use std::vector<sf::Vector2f> instead of allocating the sf::Vector2f array yourself.