I have a small problem which I can't handle.
Currently I'm working over a project about a marathon between animals.
I'm obliged to use polymorphism even though it could be easier without.
Here's a sample of my code:
class Animal
{
public:
virtual void run()=0;
virtual bool return_if_finished()=0;
virtual float return_distance()=0;
}
class Turtle :public Animal
{
int id;
float distance; //etc.
public:
void run();
bool return_if_finished();
float return_distance();
void set_id(int i);
void a_friend();
}
class Snail :public Animal
{
float distance; //etc.
public:
void run();
bool return_if_finished();
float return_distance();
void broken_leg();
}
So that's a sample. All classes that inherit from the main class "Animal" have only three mutual methods. They also have some that only they do need.
If I want to write a code in a method where they "run" like that:
...
Animal* turtles = new Turtle[amount];
Animal* snails = new Snail[amount];
for(int i=0; i<amount; i++)
turtles[i].set_id(i);
I can't compile it because "class Animal has no member called "set_id"".
I could create all these methods for each class but that would be totally pointless. I bet there's a quick solution to that.
If I create a virtual void "set_id(int)" for the class "Animal" then I get the error message that not all classes that inherit from animal contain that method.
So any help would be very appreciated. Thank you
If I create a virtual void "set_id(int)" for the class "Animal" then I get the error message that not all classes that inherit from animal contain that method.
I suspect you defined Animal::set_id as a pure virtual, like this:
virtual void set_id(int) = 0;
What you really want is to define it in the Animal class as a virtual method, like this:
virtual void set_id(int _id) {id = _id};
Also, the id member variable needs to be moved to the Animal class instead of Turtle
EDIT:
Expanding the answer to include the full code:
class Animal
{
public:
Animal() : id(-1) {}
virtual ~Animal() {}
virtual void run() = 0;
virtual bool return_if_finished() = 0;
virtual float return_distance() = 0;
void set_id(int i) { id = i; }
private:
int id;
};
class Turtle :public Animal
{
public:
void run() {};
bool return_if_finished() { return true; };
float return_distance() { return 2.0; };
void a_friend() {};
};
class Snail :public Animal
{
public:
void run() {};
bool return_if_finished() { return false; };
float return_distance() { return 1.0; };
void broken_leg() {};
};
int main()
{
const int amount = 10;
Turtle turtles[amount];
Snail snails[amount];
for (int i = 0; i < amount; i++) {
turtles[i].set_id(i);
}
}
First of all, using:
Animal* turtles = new Turtle[amount];
Animal* snails = new Snail[amount];
is a bad idea.
The pointer arithmetic on turtles and snails will be based size of Animal. If you use tutles[i] for all i not equal to 0, you'll run into undefined behavior. There is probably an SO question somewhere about that.
Use a vector of pointers instead. It will be also easier to initialize them.
std::vector<Animal*> turtles(amount); = new Turtle[amount];
for(int i=0; i<amount; i++)
{
Turtle* tptr = new Turtle;
tptr->set_id(i);
turtles[i] = tptr;
}
Better yet, use a smart pointer.
std::vector<std::shared_ptr<Animal>> turtles(amount); = new Turtle[amount];
for(int i=0; i<amount; i++)
{
Turtle* tptr = new Turtle;
tptr->set_id(i);
turtles[i] = std::shared_ptr<Animal>(tptr);
// Or
// turtles[i].reset(tptr);
}
Related
I need to create a priority_queue with abstract class "Organism" as a stored type, because I want both "Animals" and "Plants" in this queue (they derive from "Organism") but I'm not quite sure how can I do this. I've already looked for an answer but unfortunately couldn't find one that worked. Part of my code so far looks like this:
World.h:
class World
{
protected:
std::string name;
std::priority_queue<Organism, std::vector<Organism>, Compare> organisms;
public:
World(std::string name);
~World();
virtual void AddOrganism(Organism& organisms);
void EndTurn();
void DrawWorld();
};
Compare.h:
class Organism;
class Compare
{
public:
virtual bool operator()(const Organism& O1, const Organism& O2) const;
};
Organism.h:
class World;
class Organism
{
protected:
int strength, initiative, xPos, yPos, age;
World* world;
friend class Compare;
public:
virtual void Move() = 0;
virtual void Action() = 0;
virtual void Collision() = 0;
virtual void DrawMe() = 0;
};
and main:
int main()
{
SetConsoleTitle(TEXT("xxx"));
World world("World1");
Animals animal;
world.AddOrganism(animal);
system("cls");
return 0;
}
and AddOrganism method:
void World::AddOrganism(Organism& organism) {
organisms.push(organism);
};
When I try to compile this I get "Error C2259 'Organism': cannot instantiate abstract class ", anybody knows how to solve this problem?
I have these 2 classes.
class ChessPiece
{
public:
ChessPiece();
virtual bool move() = 0;
};
class Bishop: public ChessPiece
{
public:
Bishop();
bool move();
};
I'm trying to determine the type of a ChessPiece after I created it like this
ChessPiece* foo = new Bishop()
I"m trying to get the type of foo (Bishop) not ChessPiece.
Thank You
Well, there are some ways of doing this, have a look at dynamic casting:
class A
{
public:
virtual void Foo() = 0;
};
class B : public A
{
public:
void Foo() { }
};
void Test()
{
A* bar = new B();
if (B* test = dynamic_cast<B*>(bar))
{
// use test here
}
delete bar;
}
Alternatively you can store an enum in the chess piece class defining the piece id.
One example of a way to solve your problem:
enum PieceType
{
King,
Queen,
Rook,
Bishop,
Knight,
Pawn
};
class ChessPiece
{
public:
ChessPiece();
virtual ~ChessPiece();
virtual bool move() = 0;
virtual PieceType GetType() const = 0;
};
class Bishop : public ChessPiece
{
public:
Bishop();
virtual ~Bishop();
virtual bool move();
virtual PieceType GetType() const { return Bishop; }
};
Then use ChessPiece::GetType() to determine what kind of piece this is.
You can use following code.
ChessPiece obj;
Bishop* pObj = dynamic_cast<Bishop*>(&obj);//Change to Bishop,return NULL if failed.
I have a base class Animal and two derived classes Bird and Fish. I have two virtual functions, fly(int) and swim(int) in Animal for Bird and Fish respectively. There is a common function aliveSince() in Animal
class Animal{
public:
Animal() {
age = 0;
}
virtual ~Animal(){}
static Animal* factory(int type);
int aliveSince(){
return age;
}
virtual int fly(int m){} //error, needs a return value
virtual int swim(int m){} //error, needs a return value
private:
int age;
};
class Bird: public Animal{
public:
Bird(){
totalFlight = 0;
}
int fly(int m){
cout<<"Bird flew "<<m<<" metres\n";
return totalFlight = totalFlight+m;
}
private:
int totalFlight;
};
class Fish: public Animal{
public:
Fish(){
totalSwim = 0;
}
int swim(int m){
cout<<"Fish swam "<<m<<" metres underground\n";
return totalSwim = totalSwim + m;
}
private:
int totalSwim;
};
Animal* Animal::factory(int type){
if (type) return new Bird();
else return new Fish();
}
I want to use the these classes like this:
Animal *a = Animal::factory(1); //Bird
Animal *b = Animal::factory(0); //Fish
a->aliveSince();
b->aliveSince();
a->fly(5);
b->swim(5);
I am compiling in MS VC++ and it generates errors, Animal::fly and Animal::swim needs a return value. However, this compiles fine in GNU C++.
How can I get rid of the error without having to specify a return value in the virtual methods?
Note that I can't make these functions pure virtual as it would make the Animal class abstract and all derived classes will need to implement fly() and swim()
UPDATE: Just saw you can't use pure virtual methods because you need some default.
If you need a default, you'd better return it explicitly, instead of letting the compiler (or chance) decide the return value. So just return 0.
ORIGINAL
If you don't supply any implementation in your base class, use Pure Virtual methods. Like so:
class Animal
{
public:
virtual int fly(int m) = 0;
virtual int swim(int m) = 0;
};
A Pure-Virtual method is a method that has no body. It makes the Animal base class abstract - you will not be able to construct any instances of it, just of derived classes that implement these methods.
Both functions need to return a value, as you have guessed:
virtual int fly(int m){ return 0; }
virtual int swim(int m){ return 0; }
Either, put in return 0; in both scopes. That would be your answer 'as you are asking'.
Or try somything like this to simplify your code:
class Animal{
public:
Animal()
{
totalMoved = 0;
}
virtual ~Animal(){}
virtual int move( int m )
{
totalMoved += m;
cout<<"Total distance " << totalMoved << std::endl;
return totalMoved ;
}
protected:
int totalMoved;
};
class Bird: public Animal{
public:
int move(int m)
{
cout<<"Bird flew "<<m<<" metres\n";
return Animal::move( m );
}
};
class Fish: public Animal{
public:
int swim(int m){
cout<<"Fish swam "<<m<<" metres underground\n";
return Animal::move( m );
}
};
Specific algorithms to move can be written within the Bird and Fish class. The totalMove could be shared, so share it. That is the concept of OOP programming and leaves you out of doing things double.
Have added the console output in Animal too, so you can see what happens when.
I'm trying to accomplish something but am unsure if it's even possible.
The quick idea is, I'm writing a game and want to have a single array (or vector) of different monsters. Every class that inherits the main class Monster simply overrides its functions (but doesn't add any new ones).
Then, when I go through the list of monsters, I can just call the same functions that all of them have.
Here's some code to show what I'm trying to accomplish:
class Monster
{
public:
int hp; //hit points
int atp; //attack power
int def; //defense
bool attacking;
bool defending;
virtual void attack();
virtual void defend();
};
void Monster::attack()
{}
void Monster::defend()
{}
class Goblin: public Monster
{
public:
virtual void attack() override;
virtual void defend() override;
};
void Goblin::attack()
{
//Goblin's attacking patterns
}
void Goblin::defend()
{
//Goblin's defending patterns
}
class Orc: public Monster
{
public:
virtual void attack() override;
virtual void defend() override;
};
void Orc::attack()
{
//Orc's attacking patterns
}
void Orc::defend()
{
//Orc's defending patterns
}
int main(void)
{
//This is where I'm not sure what to do:
//Initialize monsters. Make some Goblins, some Orcs
int num_monsters = 10;
Monster* monster_list;
monster_list = new Monster[num_monsters];
for (int i = 0; i < num_monsters; i++)
{
int which = rand() % 2;
switch (which)
{
case 0: //Goblin
monster_list[i] = new Goblin;
break;
case 1: //Orc
monster_list[i] = new Orc;
break;
}
}
bool quit = false;
while (quit == false)
{
for (int i = 0; i < num_monsters; i++)
{
if (monster_list[i].attacking == true)
monster_list[i].attack();
if (monster_list[i].defending == true)
monster_list[i].defend();
}
}
}
Hopefully that illustrates what I'm trying to do.
I know this doesn't work, but I'm not sure how to make it work.
Thanks for any advice on this!
You'll need to use a vector of pointers to a base class.
std::vector<Monster*> monsters;
monsters.push_back(new FireDragon());
monsters.push_back(new IceDragon());
Then you'll be able to iterate through the monsters vector and call a common method.
for(auto monster = monsters.begin(); monster != monsters.end(); monster++)
{
(*monster)->attack();
}
The classes:
class Monster {
public:
virtual ~Monster() {}
virtual void attack() = 0;
};
class FireDragon : public Monster {
public:
~FireDragon();
void attack()
{
std::cout << "Fire breath!" << std::endl;
}
};
class IceDragon : public Monster {
public:
~IceDragon();
void attack()
{
std::cout << "Ice breath!" << std::endl;
}
};
As a side note be sure to create virtual destructors in the derived classes or else the base class' destructor will be called.
ETA: Here is the implementation with smart pointers:
/*
Use std::unique_ptr<Monster> if your implementation doesn't need to pass the
monster objects around
*/
std::vector<std::shared_ptr<Monster>> monsters;
/*
Use std::make_unique<FireDragon>() if using unique_ptr
*/
monsters.push_back(std::make_shared<FireDragon>());
monsters.push_back(std::make_shared<IceDragon>());
for(auto monster : monsters)
{
monster->attack();
}
I Have two classes:
First:
class Thing {
public:
int code;
string name;
string description;
int location;
bool canCarry;
Thing(int _code, string _name, string _desc, int _loc, bool _canCarry) {
code = _code;
name = _name;
description = _desc;
location = _loc;
canCarry = _canCarry;
}
};
Second:
class Door: public Thing {
private:
bool open;
public:
int targetLocation;
Door(int _code, string _name, string _desc, int _loc, int _targetLoc) :
Thing(_code, _name, _desc, _loc, false) {
open = false;
targetLocation = _targetLoc;
}
void Use() {
open = true;
}
void Close() {
open = false;
}
bool isOpen() {
return open;
}
};
Forget private/public atributes...
I need to store some objects of base class and some objects of derived class,
something like this:
vector < Thing*> allThings;
things.push_back(new Thing(THING1, "THING1", "some thing", LOC1, true));
things.push_back(new Door(DOOR1, "DOOR1", "some door", LOC1, LOC2));
But in this case, functions Use(), Open(), and isOpen() will not be reachable because of slicing..
Do you have some suggestions, how to store these objects together without creating new structure of vector<Thing*> and vector<Door*>??
Thanks
A good solution to a problem when you need a container of objects with polymorphic behavior is a vector of unique pointers:
std::vector<std::unique_ptr<Thing>>
There would be no slicing in this situation, but you would have to figure out when it's OK to call Use(), Open(), and isOpen().
If you can move the methods from the derived class into the base, go for it; if you cannot do that because it makes no sense for a Thing to have isOpen(), consider using a more advanced solution, such as the Visitor Pattern:
class Thing;
class Door;
struct Visitor {
virtual void visitThing(Thing &t) = 0;
virtual void visitDoor(Door &d) = 0;
};
class Thing {
...
virtual void accept(Visitor &v) {
v.visitThing(*this);
}
};
class Door : public Thing {
...
virtual void accept(Visitor &v) {
v.visitDoor(*this);
}
}
Store pointers instead of instances, and declare public and protected methods as virtual in the base class(es).