C++ undefined reference error in my code? - c++

My code blocks complier give 'undefined reference error to vtable Plant' to my code I have already read oteher articles in this page, but that did not resolved my issue. I tried to add both virtual and normal destructor.
Please review my code and try to run it in Code::Blocks with cpp11 and this topic is not a duplicate!
Here my code :
#include <iostream>
#include <vector>
#include <cstdlib>
#include <fstream>
#include <vector>
#include <time.h>
#include "Plant.h"
using namespace std;
int main(){
vector<Plant*> novenyek;
int novenyszam = 5;
f >> novenyszam;
novenyek.resize(novenyszam);
// novenyek[i].push_back(new Deltafa("a",0,true)); //thhis does not work
for (int i=0; i<novenyszam; i++){
/* string tempname;
string tempfajta;
string temptapanyag;
*/
// string a = "Falank";
// novenyek[i] = new Puffancs(a,7,true);
novenyek[i] = new Deltafa("a",0,true);
//new Puffancs("Falank",7,true);
//novenyek.push_back(new Puffancs("a",7,true));
// novenyek[i] = new Plant(Puffancs("nev",7,true));
// novenyek.push_back();
}
return 0;
}
Plant.h
#pragma once
#include <string>
#include <ostream>
#include <stdlib.h>
enum Sugarzas
{
ALFA,
DELTA,
NONE,
};
struct SugarzasIgeny
{
Sugarzas _sugarzas;
int _mennyiseg;
SugarzasIgeny(Sugarzas sugarzas, int mennyiseg = 0): _mennyiseg(mennyiseg), _sugarzas(sugarzas) {}
};
class Plant
{
public:
///Plant(const std::string &nev, int tapanyag, bool El_e) : _nev(nev), _tapanyag(tapanyag), _El_e(El_e) {}
std::string nev() const { return _nev; }
int tapanyag() const { return _tapanyag; }
bool El_e() const { return _El_e; }
// Sablonfuggveny
virtual SugarzasIgeny nap(Sugarzas sugarzas);
~Plant () {}
protected:
std::string _nev; //noveny neve
int _tapanyag; //tapanyaga
bool _El_e; //ele
Plant(const std::string &nev, int tapanyag, bool El_e) : _nev(nev), _tapanyag(tapanyag), _El_e(El_e) {}
};
class Puffancs : public Plant
{
public:
Puffancs(const std::string &nev, int tapanyag, bool El_e) : Plant(nev, tapanyag, El_e) {}
virtual SugarzasIgeny nap(Sugarzas sugarzas) ;
};
class Deltafa : public Plant
{
public:
Deltafa(const std::string &nev, int tapanyag, bool El_e) : Plant(nev, tapanyag, El_e) {}
virtual SugarzasIgeny nap(Sugarzas sugarzas) ;
};
class Parabokor : public Plant
{
public:
Parabokor(const std::string &nev, int tapanyag, bool El_e) : Plant(nev, tapanyag, El_e) {}
virtual SugarzasIgeny nap(Sugarzas sugarzas) ;
};
Plant.cpp
#include "Plant.h"
SugarzasIgeny Puffancs::nap(Sugarzas sugarzas)
{
switch (sugarzas)
{
case Sugarzas::ALFA :
_tapanyag += 2;
break;
case Sugarzas::DELTA :
_tapanyag -= 2;
break;
case Sugarzas::NONE :
_tapanyag -= 1;
break;
default:
break;
}
if ( _tapanyag > 0 && _tapanyag <=10){
_El_e = false;
}else {
_El_e = true;
}
return SugarzasIgeny(Sugarzas::ALFA, 10);
}
SugarzasIgeny Deltafa::nap(Sugarzas sugarzas)
{
switch (sugarzas)
{
case Sugarzas::ALFA :
_tapanyag -= 3;
break;
case Sugarzas::DELTA :
_tapanyag += 4;
break;
case Sugarzas::NONE :
_tapanyag -= 1;
break;
default:
break;
}
if (_tapanyag > 0)
{_El_e = true;}
else {_El_e = false; }
if (_tapanyag <5 ){
return SugarzasIgeny(Sugarzas::DELTA, 4);
}
else if (_tapanyag >= 5 && _tapanyag <= 10 ){
return SugarzasIgeny(Sugarzas::DELTA, 1);
}else {
return SugarzasIgeny(Sugarzas::NONE, 10);
}
}
SugarzasIgeny Parabokor::nap(Sugarzas sugarzas)
{
switch (sugarzas)
{
case Sugarzas::ALFA :
_tapanyag++;
break;
case Sugarzas::DELTA :
_tapanyag++;
break;
case Sugarzas::NONE :
_tapanyag--;
break;
default:
break;
}
// _El_e = tapanyag > 0;
if (_tapanyag > 0){_El_e = true;}
else {_El_e = false;}
return SugarzasIgeny(Sugarzas::NONE, 10);
}

Just define Plant::nap:
class Plant {
public:
...
// Probably stupid code, but just for example
virtual SugarzasIgeny nap(Sugarzas sugarzas) { return SugarzasIgeny(Sugarzas::ALFA); }
...
};
or make it pure virtual:
class Plant {
public:
...
// Pure virtual, no need for code, but class is then non instanciable
virtual SugarzasIgeny nap(Sugarzas sugarzas)=0;
...
};

Related

why do i keep getting this error: invalid initialization of non-const reference of type 'FarmAnimal&' from an rvalue of type 'FarmAnimal'|

#include <iostream>
#include <string>
#include <cstdio>
using namespace std;
class FarmAnimal {
public:
FarmAnimal(double water_consumption);
double getwaterConsumption();
// ...
private:
double water_consumption;
};
FarmAnimal::FarmAnimal(double water_consumption) {
this->water_consumption = water_consumption;
}
double FarmAnimal::getwaterConsumption() {
return water_consumption;
}
class ConsumptionAccumulator
{
public: ConsumptionAccumulator();
double getTotalConsumption();
void addConsumption(FarmAnimal& animal);
private:
double total_consumption;
};
ConsumptionAccumulator::ConsumptionAccumulator() :
total_consumption(0)
{
}
double ConsumptionAccumulator::getTotalConsumption()
{
return total_consumption;
}
void ConsumptionAccumulator::addConsumption(FarmAnimal& animal)
{
total_consumption += animal.getwaterConsumption();
}
class Cow : public FarmAnimal
{
public: Cow(double weigth) : FarmAnimal(0.086 * weigth) {}
};
class Sheep : public FarmAnimal {
public:
Sheep(double weigth) : FarmAnimal(0.11 * weigth) {}
};
class Horse : public FarmAnimal {
public:
Horse(double weigth) : FarmAnimal(0.068 * weigth) {}
};
int main()
{
ConsumptionAccumulator accumulator;
double weigth = 0;
std::string input = "";
do
{
std::getline(cin, input);
if (1 == sscanf(input.c_str(), "cow %lf", &weigth))
{
accumulator.addConsumption((Cow)(weigth));
}
else if (1 == sscanf(input.c_str(), "sheep% lf", &weigth))
{
accumulator.addConsumption(Sheep(weigth));
}
else if (1 == sscanf(input.c_str(), "horse% lf", &weigth))
{
accumulator.addConsumption(Horse(weigth));
}
} while (input != "");
cout << accumulator.getTotalConsumption() << endl;
return 0;
}
Change this
void ConsumptionAccumulator::addConsumption(FarmAnimal& animal)
{
total_consumption += animal.getwaterConsumption();
}
to this
void ConsumptionAccumulator::addConsumption(const FarmAnimal& animal)
{
total_consumption += animal.getwaterConsumption();
}
C++ has a rule that you cannot bind a non-const reference to a temporary object. When you call addConsumption here
accumulator.addConsumption((Cow)(weigth));
you are creating a temporary Cow object and trying to use that to call addConsumption but it doesn't work because of the rule I mentioned.
Don't ignore const in C++. Use const references when you can, and declare methods as const if that's what they are.

`std::shared_ptr`: is not a valid template type argument for parameter `_Ty`

Errors
Hero: undeclared identifier
std::shared_ptr: Hero is not a valid template type argument for parameter _Ty
unary ->: std::shared_ptr does not define this operator or a conversion to a type acceptable to the predefined operator
attackInput, getSkill os not a member of std::shared_ptr
void my::Weapon::hit(std::shared_ptr,std::shared_ptr): cannot convert argument 1 from std::shard_ptr<my::Hero> to std::shared_ptr
Source.cpp
#include <iostream>
#include <cstdlib>
#include <time.h>
#include <windows.h>
#include "Hero.h"
void checkLife(my::Hero* hero)
{
if (hero->is_dead())
{
delete hero;
hero = nullptr;
}
if (hero == nullptr)
{
srand(time(0));
int rand = 1 + std::rand() % 40;
if (rand > 0 && rand <= 10) hero = new my::King();
else if (rand > 10 && rand <= 20) hero = new my::Queen();
else if (rand > 20 && rand <= 30) hero = new my::Troll();
else if (rand > 30 && rand <= 40) hero = new my::Knight();
}
}
int main()
{
my::Hero* hero = nullptr;
my::Hero* enemy = nullptr;
while (true)
{
checkLife(hero);
checkLife(enemy);
hero->attackOutput(std::shared_ptr<my::Hero>(enemy));
enemy->attackOutput(std::shared_ptr<my::Hero>(hero));
system("cls");
std::cout << hero->getName() << "`s health - " << hero->getHealth() << std::endl;
std::cout << hero->getName() << "`s health - " << hero->getHealth() << std::endl;
Sleep(1000);
}
if (hero != nullptr) delete hero;
if (enemy != nullptr) delete enemy;
system("pause");
return 0;
}
Hero.h
#pragma once
#include <memory>
#include <cstdlib>
#include <time.h>
#include <string>
#include "Weapon.h"
namespace my
{
class Hero abstract
{
protected:
std::shared_ptr<Weapon> weapon;
std::string name;
int health;
int skill;
int pressure;
int nobleness;
int beauty;
virtual void attack(int damage)
{
srand(time(0));
this->health -= damage + rand() % 20 - this->getPressurel();
}
public:
Hero(std::string name, int health, int skill, int pressure, int nobleness, int beauty)
{
this->name = name;
this->health = health;
this->skill = skill;
this->pressure = pressure;
this->nobleness = nobleness;
this->beauty = beauty;
}
std::string getName() const
{
return this->name;
}
int getHealth() const
{
return this->health;
}
int getSkill() const
{
return this->skill;
}
int getPressurel() const
{
return this->pressure;
}
int getNobleness() const
{
return this->nobleness;
}
int getBeauty() const
{
return this->beauty;
}
void attackInput(const int damage)
{
this->attack(damage);
}
void attackOutput(std::shared_ptr<Hero> enemy)
{
std::shared_ptr<Hero> thisHero(this);
this->weapon->hit(std::shared_ptr<Hero>(thisHero), enemy);
}
virtual void takeWeapon(std::shared_ptr<Weapon> weapon)
{
this->weapon = weapon;
}
bool is_dead()
{
if (this->health <= 0) return true;
else return false;
}
};
class King : public Hero
{
public:
King() : Hero("King", 300, 2, 4, 10, 15) {}
};
class Queen : public Hero
{
public:
Queen() : Hero("Queen", 300, 2, 4, 10, 15) {}
};
class Troll : public Hero
{
public:
Troll() : Hero("Troll", 300, 2, 4, 10, 15) {}
};
class Knight : public Hero
{
public:
Knight() : Hero("Knight", 300, 2, 4, 10, 15) {}
};
}
Weapon.h
#pragma once
#include "Hero.h"
namespace my
{
class Weapon abstract
{
protected:
const int damage;
int wear;
public:
Weapon(int damage, int weight, int size, int wear) : damage(damage)
{
this->wear = wear;
}
Weapon() : Weapon(1, 1, 1, 1) {}
virtual void setWeaponWear(int wear)
{
this->wear = wear;
}
virtual int getWeaponDamage() const
{
return this->damage;
}
virtual int getWeaponWear() const
{
return this->wear;
}
virtual void hit(std::shared_ptr<Hero> me, std::shared_ptr<Hero> enemy) = 0;
};
class Knife : public Weapon // NOZH
{
protected:
public:
virtual void hit(std::shared_ptr<Hero> me, std::shared_ptr<Hero> enemy)
{
int damage = this->damage * me->getBeauty();
this->wear--;
enemy->attackInput(damage);
}
};
class Bow : public Weapon // LUCK
{
protected:
public:
virtual void hit(std::shared_ptr<Hero> me, std::shared_ptr<Hero> enemy)
{
int damage = this->damage * me->getNobleness();
this->wear--;
enemy->attackInput(damage);
}
};
class Ax : public Weapon // TOPOR
{
protected:
public:
virtual void hit(std::shared_ptr<Hero> me, std::shared_ptr<Hero> enemy)
{
int damage = this->damage * me->getPressurel();
this->wear--;
enemy->attackInput(damage);
}
};
class Sword : public Weapon // MECH
{
protected:
public:
virtual void hit(std::shared_ptr<Hero> me, std::shared_ptr<Hero> enemy)
{
int damage = this->damage * me->getSkill();
this->wear--;
enemy->attackInput(damage);
}
};
}
As pointed out in the comments by #WhozCraig you have a circular dependency. You need Weapon.h in Hero.h and Hero.h in Weapon.h.
The only reason you need Hero.h in Weapon.h. Is for the hit(...) function. The best solution would be to declare the hit function somewhere else. Right now the best place would be to add it to the Hero. A hero has a weapon and attacks with that weapon another hero, a weapon itself can't attack, so just from the semantics it makes more sense to have the hit function inside the hero class.
You can probably get it to compile by splitting the code up into a header (.h) and source file (.cpp) and having a forward declaration of Hero in Weaopon.h. But this will not fix the underlying problem and the design is still flawed and will probably cause even more problems if functionality is extended.

Exception raised: read access violation. std :: shared_ptr <Weapon> :: operator -> <Weapon, 0> (...) returned nullptr., happened

PROBLEM
Exception occurs during program startup and during debugging. Exceptions occur when retrieving data using the get ???? () methods; Weapon class. The exception looks like this:
An exception occurred: violation of reading rights. std :: shared_ptr :: operator -> (...) returned nullptr. The code in Hero.h comments out the problem fragments, method calls.
Main.cpp
#include "Hero.h"
#include <iostream>
#include <windows.h>
#include <cstdlib>
#include <time.h>
Hero* GetSomeHero()
{
switch (1 + rand() % 5)
{
case 1: return new Human(100);
case 2: return new King(300);
case 3: return new Queen(150);
case 4: return new Knight(200);
case 5: return new Troll(250);
}
return new Human(100);
}
int main()
{
srand((unsigned int)time(0));
std::shared_ptr<Hero> hero(GetSomeHero());
std::shared_ptr<Hero> enemy(GetSomeHero());
while (true)
{
hero->attackOutput(*enemy);
enemy->attackOutput(*hero);
if (hero->isDead())
{
std::shared_ptr<Hero> temp(GetSomeHero());
hero.swap(temp);
}
if (enemy->isDead())
{
std::shared_ptr<Hero> temp(GetSomeHero());
enemy.swap(temp);
}
std::cout << *hero << std::endl << *enemy << std::endl;
Sleep(200);
system("cls");
}
system("pause");
return 0;
}
Weapon.h
#pragma once
#include <string>
class Weapon
{
protected:
std::string name;
float damage;
int wear;
public:
Weapon(std::string name, float damage, int wear)
{
this->name = name;
this->damage = damage;
this->wear = wear;
}
virtual void setWear(int wear) = 0;
virtual std::string getName() = 0;
virtual float getDamage() = 0;
virtual int getWear() = 0;
};
class Fist : public Weapon // KULAK
{
protected:
public:
Fist() : Weapon("Fist", 1, 3) {}
virtual void setWear(int wear)
{
this->wear = wear;
}
virtual std::string getName()
{
return this->name;
}
virtual float getDamage()
{
return this->damage;
}
virtual int getWear()
{
return this->wear;
}
};
class Knife : public Weapon // NOZH
{
protected:
public:
Knife() : Weapon("Knife", 5, 5) {}
virtual void setWear(int wear)
{
this->wear = wear;
}
virtual std::string getName()
{
return this->name;
}
virtual float getDamage()
{
return this->damage;
}
virtual int getWear()
{
return this->wear;
}
};
class Bow : public Weapon // LUCK
{
protected:
public:
Bow() : Weapon("Bow", 15, 10) {}
virtual void setWear(int wear)
{
this->wear = wear;
}
virtual std::string getName()
{
return this->name;
}
virtual float getDamage()
{
return this->damage;
}
virtual int getWear()
{
return this->wear;
}
};
class Ax : public Weapon // TOPOR
{
protected:
public:
Ax() : Weapon("Ax", 30, 5) {}
virtual void setWear(int wear)
{
this->wear = wear;
}
virtual std::string getName()
{
return this->name;
}
virtual float getDamage()
{
return this->damage;
}
virtual int getWear()
{
return this->wear;
}
};
class Sword : public Weapon // MECH
{
protected:
public:
Sword() : Weapon("Sword", 25, 8) {}
virtual void setWear(int wear)
{
this->wear = wear;
}
virtual std::string getName()
{
return this->name;
}
virtual float getDamage()
{
return this->damage;
}
virtual int getWear()
{
return this->wear;
}
};
Hero.h
#include "Weapon.h"
#include <iostream>
#include <string>
#include <cstdlib>
class Hero
{
protected:
std::shared_ptr<Weapon> weapon;
std::string name;
float health;
int pressure;
int beauty;
int skill;
int horror;
public:
Hero(std::string name, float health, int pressure, int beauty, int skill, int horror)
{
this->name = name;
this->health = health;
this->pressure = 1 + rand() % pressure;;
this->beauty = 1 + rand() % beauty;
this->skill = 1 + rand() % skill;
this->horror = 1 + rand() % horror;
}
friend std::ostream& operator<<(std::ostream& os, const Hero& obj)
{
os << std::endl
<< obj.name << std::endl
<< "Health: " << obj.health << std::endl
/*<< "Weapon: " << obj.weapon->getName() << "[" << obj.weapon->getDamage() << "]\n"*/
<< "Specifications:\n"
<< "Pressure[" << obj.pressure << "], Beauty[" << obj.beauty << "], Skill[" << obj.skill << "], Horror[" << obj.pressure << "]\n";
return os;
}
bool isDead()
{
if (this->health > 0) return false;
else return true;
}
virtual void weaponСhange() = 0;
virtual void attackOutput(Hero& enemy) = 0;
virtual void attackInput(int damage) = 0;
};
class Human : public Hero
{
protected:
public:
Human(float health) : Hero("Human", health, 1, 1, 1, 1) {}
virtual void weaponСhange()
{
weapon = std::shared_ptr<Weapon>(new Fist);
}
virtual void attackOutput(Hero& enemy)
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
enemy.attackInput(1 /*+ (int)this->weapon->getDamage()*/);
/*this->weapon->setWear(this->weapon->getWear() - 1);*/
}
virtual void attackInput(int damage)
{
this->health -= damage;
}
};
class King : public Hero
{
protected:
public:
King(float health) : Hero("King", health, 10, 15, 4, 3) {}
virtual void weaponСhange()
{
switch (1 + rand() % 3)
{
case 1: weapon = std::shared_ptr<Weapon>(new Fist);
case 2: weapon = std::shared_ptr<Weapon>(new Knife);
case 3: weapon = std::shared_ptr<Weapon>(new Ax);
case 4: weapon = std::shared_ptr<Weapon>(new Sword);
}
}
virtual void attackOutput(Hero& enemy)
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
enemy.attackInput(1 + this->pressure + this->skill /*+ (int)this->weapon->getDamage()*/);
/*this->weapon->setWear(this->weapon->getWear() - 1);*/
}
virtual void attackInput(int damage)
{
this->health -= damage;
}
};
class Queen : public Hero
{
protected:
public:
Queen(float health) : Hero("Queen", health, 2, 15, 10, 1) {}
virtual void weaponСhange()
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
switch (1 + rand() % 2)
{
case 1: weapon = std::shared_ptr<Weapon>(new Fist);
case 2: weapon = std::shared_ptr<Weapon>(new Knife);
case 3: weapon = std::shared_ptr<Weapon>(new Bow);
}
}
virtual void attackOutput(Hero& enemy)
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
enemy.attackInput(1 + this->beauty + this->skill /*+ (int)this->weapon->getDamage()*/);
/*this->weapon->setWear(this->weapon->getWear() - 1);*/
}
virtual void attackInput(int damage)
{
this->health -= damage;
}
};
class Knight : public Hero
{
protected:
public:
Knight(float health) : Hero("Knight", health, 15, 6, 20, 1) {}
virtual void weaponСhange()
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
switch (1 + rand() % 2)
{
case 1: weapon = std::shared_ptr<Weapon>(new Fist);
case 2: weapon = std::shared_ptr<Weapon>(new Ax);
case 3: weapon = std::shared_ptr<Weapon>(new Sword);
}
}
virtual void attackOutput(Hero& enemy)
{
if (weapon->getWear() <= 0) this->weaponСhange();
enemy.attackInput(1 + this->skill + this->pressure /*+ (int)this->weapon->getDamage()*/);
/*this->weapon->setWear(this->weapon->getWear() - 1);*/
}
virtual void attackInput(int damage)
{
this->health -= damage;
}
};
class Troll : public Hero
{
protected:
public:
Troll(float health) : Hero("Troll", health, 20, 1, 1, 10) {}
virtual void weaponСhange()
{
/*if (this->weapon->getWear() <= 0) this->weaponСhange();*/
switch (1 + rand() % 1)
{
case 1: weapon = std::shared_ptr<Weapon>(new Fist);
case 2: weapon = std::shared_ptr<Weapon>(new Ax);
}
}
virtual void attackOutput(Hero& enemy)
{
if (weapon->getWear() <= 0) this->weaponСhange();
enemy.attackInput(1 + this->horror + this->pressure /*+ (int)this->weapon->getDamage()*/);
/*this->weapon->setWear(this->weapon->getWear() - 1);*/
}
virtual void attackInput(int damage)
{
this->health -= damage;
}
};
The problem causing the crashes is most probably that you call weapon->getWear() in attackOutput() for Knight and Troll. You do this before you've assigned a weapon to them.
Another problem: You haven't made the bases classes destructors virtual. This means that the smart pointer will only destroy the base class part of the object when it's time to destroy it.
A third problem: Many of your switches assign variables, but don't break so the values will be overwritten over and over again and will finally be assigned the value in the last case. In this case, you'll get a random number, [1, 3] (not [1, 4]), and you'll get a Sword every time.
switch (1 + rand() % 3)
{
case 1: weapon = std::shared_ptr<Weapon>(new Fist); // missing break;
case 2: weapon = std::shared_ptr<Weapon>(new Knife); // missing break;
case 3: weapon = std::shared_ptr<Weapon>(new Ax); // missing break;
case 4: weapon = std::shared_ptr<Weapon>(new Sword); // missing break;
}
Sidenotes:
Prefer weapon = std::make_shared<Fist>(); etc. instead of the above.
Prefer std::unique_ptr over std::shared_ptr unless you actually need reference counted pointers.
Pick one type for damage and health etc. You now use a mix of float and int.
When you override a member function in a subclass, you can skip the virtual specifier (it does not matter) and instead add the override specifier. This will make the compiler complain if the function doesn't actually override a virtual function.
In logical expressions as
bool isDead() {
if (this->health > 0) return false;
else return true;
}
you already have a boolean result inside the if(...) so prefer to return it directly. In this case, you can simply do this instead:
bool isDead() {
return this->health <= 0;
}
Use the <random> random number generators and support functions for better randomization. Since you generate a lot of numbers between 1 and some max value (inclusive), you could make a support function for it. Example:
#include <random>
int my_rand(int max) {
// the generator will only be seeded once since it's static
static std::mt19937 generator(std::random_device{}());
std::uniform_int_distribution<int> dist(1, max); // range: [1, max]
return dist(generator);
}
If you have a default implementation for some of the virtual functions, you can implement it in the base class to save youself a lot of copy/pasting. Only override it in those cases you want something special. Example for a few Weapons:
class Weapon {
private:
// Direct access to member variables is usually not a good idea. Try to keep them
// private.
std::string name;
float damage;
int wear;
protected:
// The constructor can be protected, only subclasses will be able to use it.
Weapon(std::string Name, float Damage, int Wear) : // use the initializer list
name(Name), damage(Damage), wear(Wear)
{}
// virtual destructor
virtual ~Weapon() = default;
public:
virtual void setWear(int Wear) { wear = Wear; }
virtual void applyWear() { --wear; }
virtual const std::string& getName() { return name; }
virtual float getDamage() const { return damage; }
virtual int getWear() { return wear; }
};
class Fist : public Weapon // KULAK
{
public:
Fist() : Weapon("Fist", 1, 3) {}
};
class Knife : public Weapon // NOZH
{
public:
Knife() : Weapon("Knife", 5, 5) {}
};
...

Make a collection of an abstract class type, Abstract Class vector of shared_ptr

Error
e/c++/v1/algorithm:642:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/utility:321:9: error:
field type 'Space' is an abstract class
_T2 second;
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/map:624:16: note:
Question
How can I define a std::vector of type Space which is an abstract class and then fill this vector with instances of the derived classes Empty, Snake, Ladder.
Context
I know abstract classes in C++ can not be instantiated. Instead I've read in several posts on this and other sites that you can create a collection of an abstract type if it the type is defined as a star * pointer or any of the <memory> managed pointer data types like std::unqiue_ptr<T>. I've tried to used shared_ptr<Space> in my case, but still unable to define the collection properly. I am compiled my code using g++ -std=c++17 main.cpp && ./a.out.
Code
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <map>
#include <memory>
#include <typeinfo>
#include <queue>
#include <string>
#include <vector>
class Player
{
private:
int m_current_space = 1;
public:
Player() {}
void role_dice() {
m_current_space += floor( (rand()%10 + 1) / 3 );
}
int const get_current_space() {
return m_current_space;
}
void set_current_space(int current_space) {
m_current_space = current_space;
}
};
class Space
{
protected:
int m_id;
std::vector<Space> m_paths;
public:
Space() {} // requied to use [] operator in map
Space(int id) : m_id(id) {}
void add_path(Space& s) {
m_paths.push_back(s);
}
int get_id() {
return m_id;
}
virtual std::string class_type() = 0;
};
class Empty : public Space
{
public:
Empty(int id) : Space(id) {}
std::string class_type() {
return "Empty";
}
};
class Ladder : public Space
{
public:
Ladder(int id) : Space(id) {}
virtual void event(Player& p) {
p.set_current_space(1);
}
std::string class_type() {
return "Ladder";
}
};
class Snake : public Space
{
public:
Snake(int id) : Space(id) {}
virtual void event(Player& p) {
p.set_current_space(4);
}
std::string class_type() {
return "Snake";
}
};
class Board
{
private:
std::map<int, Space> m_board;
public:
void add_space(Space& s) {
m_board[s.get_id()] = s;
}
void draw_board() {
int i = 1;
for(auto const& [space_key, space] : m_board) {
if(i%3 == 0) {
std::cout << "○\n";
}
else if(typeid(space) == typeid(Snake)) {
std::cout << "○-";
}
else {
std::cout << "○ ";
}
++i;
}
}
void update_player_on_board(int position) {
int i = 1;
for(auto const& [space_key, space] : m_board) {
if(i%3 == 0) {
if (space_key == position) {
std::cout << "●\n";
}
else {
std::cout << "○\n";
}
}
else if(typeid(space) == typeid(Snake)) {
std::cout << "○-";
}
else {
if (space_key == position) {
std::cout << "● ";
}
else {
std::cout << "○ ";
}
}
++i;
}
}
const std::map<int, Space> get_board() {
return m_board;
}
friend std::ostream &operator<<(std::ostream& os, const Board& b) {
return os;
}
};
class GameStateManager
{
private:
std::string m_state = "game over";
bool m_playing = false;
public:
std::string const get_state() {
return m_state;
}
void set_state(std::string state) {
m_state = state;
}
};
int main()
{
std::cout << "Welcome to Bowser's 9 board game\n";
std::cout << "Start? y(yes) n(no)\n";
GameStateManager game_manager;
game_manager.set_state("playing");
auto space1 = std::make_shared<Space>(1);
auto space2 = std::make_shared<Space>(2);
auto space3 = std::make_shared<Space>(3);
auto space4 = std::make_shared<Space>(4);
auto space5 = std::make_shared<Space>(5);
auto space6 = std::make_shared<Space>(6);
auto space7 = std::make_shared<Space>(7);
auto space8 = std::make_shared<Space>(8);
auto space9 = std::make_shared<Space>(9);
std::vector<std::shared_ptr<Space>> v {
space1, space2, space3,
space4, space5, space6,
space7, space8, space9
};
Board bowsers_bigbad_laddersnake;
for(int i = 0; i < 10; ++i) {
bowsers_bigbad_laddersnake.add_space(*(v[i]));
}
bowsers_bigbad_laddersnake.draw_board();
Player mario;
int turn = 0;
while(game_manager.get_state() == "playing") {
std::cin.get();
std::cout << "-- Turn " << ++turn << " --" << '\n';
mario.role_dice();
bowsers_bigbad_laddersnake.update_player_on_board(mario.get_current_space());
if (mario.get_current_space() >= 9) {
game_manager.set_state("game over");
}
}
std::cout << "Thanks a so much for to playing!\nPress any key to continue . . .\n";
std::cin.get();
return 0;
}
You seem to have removed a lot of code to get into details here.
Have a Space pointer (smart or raw). Instantiate the specific space that you want, point to it with your pointer of type Space. Example std::shared_ptr<Space> pointerToSpace = std::make_shared<Snake> ("I'm a snake"); Now, without loss of generality, you can print the contents (of concrete type) with just the pointer to the space pointerToSpace->class_type(). Yes, you can have a collection of shared_ptrs in a container.

Unable to solve the "error: candidate is:" in cocos2dx

I'm currently having a problem with the following error when I try to run my game. I tried to understand what the meaning of the following error but I find it hard to understand. I believe that there is more than one error but I have no clue where to look. I would love to have some help from you!
[armeabi] Compile++ thumb: MyGame_shared <= BallSprite.cpp
[armeabi] Compile++ thumb: MyGame_shared <= Character.cpp
[armeabi] StaticLibrary : libcocos2d.a
[armeabi] StaticLibrary : libcocostudio.a
[armeabi] StaticLibrary : libcocosbuilder.a
[armeabi] StaticLibrary : libcocos3d.a
jni/../../../Classes/Character.cpp:26:5: error: prototype for 'int Character::getTurnCount()' does not match any in class 'Character'
int Character::getTurnCount()
^
In file included from /Users/michael/Desktop/CocoFolder/Puzzle/cocos2d/cocos/3d/../base/CCAsyncTaskPool.h:28:0,
from /Users/michael/Desktop/CocoFolder/Puzzle/cocos2d/cocos/3d/../cocos2d.h:41,
from jni/../../../Classes/Character.h:4,
from jni/../../../Classes/Character.cpp:1:
/Users/michael/Desktop/CocoFolder/Puzzle/cocos2d/cocos/3d/../platform/CCPlatformMacros.h:153:25: error: candidate is: virtual int Character::getTurnCount() const
public: virtual varType get##funName(void) const;\
^
jni/../../../Classes/Character.h:26:5: note: in expansion of macro 'CC_PROPERTY'
CC_PROPERTY(int, _turnCount, TurnCount);
^
jni/../../../Classes/BallSprite.cpp:62:27: error: prototype for 'BallSprite::PositionIndex BallSprite::getPositionIndex()' does not match any in class 'BallSprite'
BallSprite::PositionIndex BallSprite::getPositionIndex()
^
In file included from /Users/michael/Desktop/CocoFolder/Puzzle/cocos2d/cocos/3d/../base/CCAsyncTaskPool.h:28:0,
from /Users/michael/Desktop/CocoFolder/Puzzle/cocos2d/cocos/3d/../cocos2d.h:41,
from jni/../../../Classes/BallSprite.h:4,
from jni/../../../Classes/BallSprite.cpp:1:
/Users/michael/Desktop/CocoFolder/Puzzle/cocos2d/cocos/3d/../platform/CCPlatformMacros.h:153:25: error: candidate is: virtual BallSprite::PositionIndex BallSprite::getPositionIndex() const
public: virtual varType get##funName(void) const;\
^
jni/../../../Classes/BallSprite.h:53:5: note: in expansion of macro 'CC_PROPERTY'
CC_PROPERTY(PositionIndex, _positionIndex, PositionIndex);
^
make: *** [obj/local/armeabi/objs-debug/MyGame_shared/__/__/__/Classes/BallSprite.o] Error 1
make: *** Waiting for unfinished jobs....
make: *** [obj/local/armeabi/objs-debug/MyGame_shared/__/__/__/Classes/Character.o] Error 1
make: Leaving directory `/Users/michael/Desktop/CocoFolder/Puzzle/proj.android-studio/app'
Error running command, return code: 2.
code for the character
#include "Character.h"
USING_NS_CC;
Character::Character()
: _hp(0)
, _maxHp(0)
, _attack(0)
, _element(Element::None)
, _turnCount(0)
, _remainingTurn(0)
{
}
Character* Character::create()
{
Character *pRet = new Character();
pRet->autorelease();
return pRet;
}
int Character::getTurnCount()
{
return _turnCount;
}
void Character::setTurnCount(int turnCount)
{
_turnCount = turnCount;
_remainingTurn = _turnCount;
}
float Character::getHpPercentage()
{
return _hp * 100.f / _maxHp;
}
bool Character::isAttackTurn()
{
_remainingTurn--;
if (_remainingTurn <= 0)
{
_remainingTurn = _turnCount;
return true;
}
return false;
}
int Character::getDamage(int ballCount, int chainCount, Character* attacker, Character* defender)
{
float baseDamage = ballCount / 3.0 * 100;
float chainBonus = powf(1.1, chainCount - 1);
float elementBonus = getElementBonus(attacker->getElement(), defender->getElement());
return baseDamage * chainBonus * elementBonus;
}
float Character::getElementBonus(Element attackElement, Element defenseElement)
{
switch (attackElement)
{
case Element::Fire:
{
switch (defenseElement)
{
case Element::Wind:return 2;
case Element::Water:return 0.5;
default:return 1;
}
break;
}
case Element::Water:
{
switch (defenseElement)
{
case Element::Fire:return 2;
case Element::Wind:return 0.5;
default:return 1;
}
break;
}
case Element::Wind:
{
switch (defenseElement)
{
case Element::Water:return 2;
case Element::Wind:return 0.5;
default:return 1;
}
break;
}
case Element::Holy:
{
switch (defenseElement)
{
case Element::Shadow:return 2;
default:return 1;
}
break;
}
case Element::Shadow:
{
switch (defenseElement)
{
case Element::Holy:return 2;
default:return 1;
}
break;
}
default:
{
return 1;
}
}
}
Characters header
class Character : public cocos2d::Ref
{
public:
enum class Element
{
Fire,
Water,
Wind,
Holy,
Shadow,
None,
};
protected:
int _remainingTurn;
CC_SYNTHESIZE(int, _hp, Hp);
CC_SYNTHESIZE(int, _maxHp, MaxHp);
CC_SYNTHESIZE(int, _attack, Attack);
CC_SYNTHESIZE(Element, _element, Element);
CC_PROPERTY(int, _turnCount, TurnCount);
public:
Character();
static Character* create();
float getHpPercentage();
bool isAttackTurn();
static int getDamage(int ballCount, int chainCount, Character* attacker, Character* defender);
protected:
static float getElementBonus(Element attackElement, Element defenseElement);
};
#endif
BallSprite.cpp
#include "BallSprite.h"
USING_NS_CC;
BallSprite::BallSprite()
: _removedNo(0)
, _checkedX(false)
, _checkedY(false)
, _fallCount(0)
, _positionIndex(0, 0)
{
}
BallSprite* BallSprite::create(BallType type, bool visible)
{
BallSprite *pRet = new BallSprite();
if (pRet && pRet->init(type, visible))
{
pRet->autorelease();
return pRet;
}
else
{
delete pRet;
pRet = nullptr;
return nullptr;
}
}
bool BallSprite::init(BallType type, bool visible)
{
if (!Sprite::initWithFile(getBallImageFilePath(type)))
return false;
_ballType = type;
setVisible(visible);
return true;
}
void BallSprite::resetParams()
{
_removedNo = 0;
_checkedX = false;
_checkedY = false;
_fallCount = 0;
}
void BallSprite::resetPosition()
{
setPosition(getPositionForPositionIndex(_positionIndex));
}
void BallSprite::getPositionIndex()
{
return _positionIndex;
}
void BallSprite::setPositionIndex(PositionIndex positionIndex)
{
_positionIndex = positionIndex;
setTag(generateTag(_positionIndex));
}
void BallSprite::setPositionIndexAndChangePosition(PositionIndex positionIndex)
{
setPositionIndex(positionIndex);
resetPosition();
}
void BallSprite::removingAndFallingAnimation(int maxRemovedNo)
{
removingAnimation(maxRemovedNo);
fallingAnimation(maxRemovedNo);
}
void BallSprite::removingAnimation(int maxRemovedNo)
{
if (_removedNo > 0)
{
auto delay1 = DelayTime::create(ONE_ACTION_TIME * (_removedNo - 1));
auto fade = FadeTo::create(ONE_ACTION_TIME, 0);
auto delay2 = DelayTime::create(ONE_ACTION_TIME * (maxRemovedNo - _removedNo));
auto removeSelf = RemoveSelf::create(false);
runAction(Sequence::create(delay1, fade, delay2, removeSelf, nullptr));
}
}
void BallSprite::fallingAnimation(int maxRemovedNo)
{
if (_fallCount > 0)
{
setPositionIndex(PositionIndex(_positionIndex.x, _positionIndex.y - _fallCount));
auto delay = DelayTime::create(ONE_ACTION_TIME * maxRemovedNo);
auto show = Show::create();
auto move = MoveTo::create(ONE_ACTION_TIME, getPositionForPositionIndex(getPositionIndex()));
runAction(Sequence::create(delay, show, move, nullptr));
}
}
std::string BallSprite::getBallImageFilePath(BallType type)
{
switch (type)
{
case BallType::Red: return "red.png";
case BallType::Blue: return "blue.png";
default: return "pink.png";
}
}
Point BallSprite::getPositionForPositionIndex(PositionIndex positionIndex)
{
return Point(BALL_SIZE * (positionIndex.x - 0.5) + 1,
BALL_SIZE * (positionIndex.y - 0.5) + 1);
}
int BallSprite::generateTag(PositionIndex positionIndex)
{
return positionIndex.x * 10 + positionIndex.y;
}
BallSprite header
#include "cocos2d.h"
#define BALL_SIZE 106
#define ONE_ACTION_TIME 0.2
class BallSprite : public cocos2d::Sprite
{
public:
enum class BallType
{
Blue,
Red,
Green,
Yellow,
Purple,
Pink,
};
struct PositionIndex
{
PositionIndex()
{
x = 0;
y = 0;
}
PositionIndex(int _x, int _y)
{
x = _x;
y = _y;
}
int x;
int y;
};
BallSprite();
static BallSprite* create(BallType type, bool visible);
virtual bool init(BallType type, bool visible);
CC_SYNTHESIZE(int, _removedNo, RemovedNo);
CC_SYNTHESIZE(bool, _checkedX, CheckedX);
CC_SYNTHESIZE(bool, _checkedY, CheckedY);
CC_SYNTHESIZE(int, _fallCount, FallCount);
CC_SYNTHESIZE_READONLY(BallType, _ballType, BallType);
CC_PROPERTY(PositionIndex, _positionIndex, PositionIndex);
void setPositionIndexAndChangePosition(PositionIndex positionIndex);
void resetParams();
void resetPosition();
void removingAndFallingAnimation(int maxRemovedNo);
static std::string getBallImageFilePath(BallType type);
static cocos2d::Point getPositionForPositionIndex(PositionIndex positionIndex);
static int generateTag(PositionIndex positionIndex);
protected:
void removingAnimation(int maxRemovedNo);
void fallingAnimation(int maxRemovedNo);
};
#endif
CC_PROPERTY(int, _turnCount, TurnCount);
virtual method definition should be like this because in declaration it is constant.
int Character::getTurnCount() const
{
return _turnCount;
}
And there is problem in return type of getter method, it should be like this.
CC_PROPERTY(PositionIndex, _positionIndex, PositionIndex);
PositionIndex BallSprite::getPositionIndex() const
{
return _positionIndex;
}
EDIT
You can't directly access PositionIndex, use it with BallSprite
BallSprite::PositionIndex BallSprite::getPositionIndex() const
{
return _positionIndex;
}