I want to have classes named chessman and pawn, for example. I can't make chessman an abstract class because I need to create an 2D array of it. pawn class inherits chessman and I need to use move function of pawn when I write this:
chessman *cm = new pawn("a3", 'w');
cm->move(pos);
This code uses chessman::move. What can I do to make it use the one from pawn class? My question is very similar to this question, but my function doesn't take pawn as an argument. In Java, it's easy since you can create arrays of abstract classes, but in C++ it is just confusing.
EDIT:
Here is definition of chessman class (function already is virtual as you can see):
class chessman
{
public:
int i;
int j;
string name;
char color;
virtual bool move(string final_pos);
};
And pawn:
class pawn : public chessman
{
public:
pawn(string pos, char color);
bool move(string final_pos);
};
I can't make chessman an abstract class because I need to create an 2D array of it.
Yes, you can. You don't create an array of chessman objects, you create an array of pointers to chessman objects. Then chessman can be abstract (as it should be, since you should not be creating instances of chessman directly to begin with).
pawn class inherits chessman and I need to use move function of pawn when I write this
Polymorphism handles that for you. But in order to use an array of polymorphic objects, the array needs to hold pointers/references to objects that are stored elsewhere in memory, not hold the actual objects themselves.
In Java, it's easy since you can create arrays of abstract classes, but in C++ it is just confusing.
You do the exact same thing in C++. In Java, objects are reference types, so they are always referenced by pointer (the Java language simply hides that detail from you).
Try something like this:
class chessman
{
private:
virtual bool isValidMove(string final_pos) = 0;
public:
int i;
int j;
string name;
char color;
chessman(string aname, char acolor);
bool move(string final_pos);
};
chessman::chessman(string aname, char acolor)
: name(aname), color(acolor)
{
}
bool chessman::move(string final_pos)
{
// validate that final_pos is a valid position on the board...
// validate that final_pos is a valid position for the piece being moved...
if (!isValidMove(final_pos))
return false;
// move to the position...
return true;
}
class pawn : public chessman
{
private:
virtual bool isValidMove(string final_pos);
public:
pawn(string pos, char color);
};
pawn::pawn(string pos, char color)
: chessman("pawn", color)
{
//...
}
bool pawn::isValidMove(string final_pos)
{
// validate that final_pos is a valid position for this pawn to move to...
return ...;
}
class rook : public chessman
{
private:
virtual bool isValidMove(string final_pos);
public:
rook(string pos, char color);
};
rook::rook(string pos, char color)
: chessman("rook", color)
{
//...
}
bool rook::isValidMove(string final_pos)
{
// validate that final_pos is a valid position for this rook to move to...
return ...;
}
class knight : public chessman
{
private:
virtual bool isValidMove(string final_pos);
public:
knight(string pos, char color);
};
knight::knight(string pos, char color)
: chessman("knight", color)
{
//...
}
bool knight::isValidMove(string final_pos)
{
// validate that final_pos is a valid position for this knight to move to...
return ...;
}
class bishop : public chessman
{
private:
virtual bool isValidMove(string final_pos);
public:
bishop(string pos, char color);
};
bishop::bishop(string pos, char color)
: chessman("bishop", color)
{
//...
}
bool bishop::isValidMove(string final_pos)
{
// validate that final_pos is a valid position for this bishop to move to...
return ...;
}
class queen : public chessman
{
private:
virtual bool isValidMove(string final_pos);
public:
queen(string pos, char color);
};
queen::queen(string pos, char color)
: chessman("queen", color)
{
//...
}
bool queen::isValidMove(string final_pos)
{
// validate that final_pos is a valid position for this queen to move to...
return ...;
}
class king : public chessman
{
private:
virtual bool isValidMove(string final_pos);
public:
king(string pos, char color);
};
king::king(string pos, char color)
: chessman("king", color)
{
//...
}
bool king::isValidMove(string final_pos)
{
// validate that final_pos is a valid position for this king to move to...
return ...;
}
Then you can do somthing like this:
chessman* white_pieces[16];
chessman* black_pieces[16];
for (int i = 0; i < 8; ++i)
{
white_pieces[i] = new pawn(...);
black_pieces[i] = new pawn(...);
}
for (int i = 8; i < 10; ++i)
{
white_pieces[i] = new rook(...);
black_pieces[i] = new rook(...);
}
for (int i = 10; i < 12; ++i)
{
white_pieces[i] = new knight(...);
black_pieces[i] = new knight(...);
}
for (int i = 12; i < 14; ++i)
{
white_pieces[i] = new bishop(...);
black_pieces[i] = new bishop(...);
}
white_pieces[14] = new queen(...);
black_pieces[14] = new queen(...);
white_pieces[15] = new king(...);
black_pieces[15] = new king(...);
And move them around as needed:
white_pieces[index]->move(pos);
...
black_pieces[index]->move(pos);
And of course, don't forget to cleanup when you are done:
for (int i = 0; i < 16; ++i)
{
delete white_pieces[i];
delete black_pieces[i];
}
To make the cleanup automatic, you can use an array of std::auto_ptr<chessman> objects. Or, in C++11 and later, a std::vector/std::array of std::unique_ptr<chessman> objects.
In C++ you would create a vector (or possibly array in C++11) of some sort of pointer (the pointer type would be dictated by the object ownership) to a chessman, and have chessman be abstract. It's just a slightly different way of thinking about things.
(Edited as the comments made a great point):
To make it select the proper move function, utilize the virtual mechanism in the base class. I would suggest to separate interface from implementation by not having public virtual functions. Instead, use a public non-virtual interface and a private or protected virtual implementation. You would use a private implementation which each child totally replaces the functionality while you would use protected when the child class needs to also invoke the parent functionality.
Related
Consider the following code
class Shape
{
protected:
int length, height;
public:
Shape();
~Shape();
};
class Square : Shape
{
private:
double Area;
public:
Square();
~Square();
};
class Circle : Shape
{
private:
double Circumference;
public:
Circle();
~Circle();
};
int main()
{
Shape *shape[5];
int choice, i = 0;
cout << "Which shape are you making?\n";
cout << "1. Square\n";
cout << "2. Circle\n";
cin >> choice;
if (choice == 1)
{
shape[i] = new Square();
i++;
}
if (choice == 2)
{
shape[i] = new Circle();
i++;
}
}
How would I make an array of pointers that contain both Circle and Squares so I can easily access both later to do stuff with it? Currently, it is giving me an error in the shape[i] = new Square(); and shape[i] = new Circle(); in main() and I don't know how to create an array of pointers to inherited classes.
You need to specify what kind of inheritance you want; More specifically, you need to tell the compiler that it is a public inheritance, meaning, that your entire code-base can know that Circle and Square are Shape.
Just change the declaration of the classes into:
class Circle : public Shape
class Square : public Shape
Also, consider having Shape as a true virtual interface, meaning - it should have nothing other than the public API that each shape should have, for example:
class IShape
{
public:
virtual double get_area() const = 0;
virtual double get_perimeter() const = 0;
// and so on...
virtual ~IShape() = 0;
protected:
virtual double calculate_something() const = 0;
// also protected can be here
};
Also, notice that using raw arrays, and especially raw arrays of raw pointers, such as:
Shape *shape[5];
is a good way to cause memory leak in your program; You should use both std::array and std::unique_ptr<IShape> in this context, meaning, your main should look like:
std::array<std::unique_ptr<IShape>, 5> shape;
int choice = 1;
int i = 0;
if (choice == 1)
{
shape[i] = std::unique_ptr<IShape>(new Square());
i++;
}
if (choice == 2)
{
shape[i] = std::unique_ptr<IShape>(new Circle());
i++;
}
It is because you are specifying the inheritance without telling whether it is public, private or protected . By default c++ will consider it private so you are not allowed to access a private class . change the inheritance from private to public and you are good to go .
something like this
class Square :public Shape
{
private:
double Area;
public:
Square();
~Square();
};
class Circle :public Shape
{
private:
double Circumference;
public:
Circle();
~Circle();
};
I have a Geometry class
class Geometry
{
public:
std::string stdstrType;
bool bValid;
public:
Geometry()
Geometry( std::string strType , bool bValue )
Geometry(const Geometry &g)
~Geometry()
virtual void draw();
bool isValid();
void setValidState(bool bState);
virtual void Init();
std::string GetName();
};
Which is the base class for Geometry objects like in this case for Sphere class
class Sph : public Geometry
{
public:
Sph( float radius , float segments );
~Sph();
void init();
void CleanUp();
void draw();
private:
float fRadius, fSegments;
bool isInited;
unsigned int m_VAO, m_VBO;
int iNumsToDraw;
SumShader shader;
bool isChanged;
};
I have a Tree structure holding different Container objects and Geometry is a data type in the Container object.
class Container
{
private:
std::string stdstrContainerName;
std::string stdstrPluginType;
Geometry Geom;
}
Since each item in the tree can hold a circle sphere or rectangle so I would like to use the draw function of geometry to draw the Geometry object types.
For this when I try to cast any Geometry Object type to Geometry I get an error.
Sph sphere(0.1 , 32);
Geometry *geom = &sphere;
Container cont("Sphere" , "SPHERE" , *geometry );
myModel->SetContainer(child, cont);
The Constructor for Container
Container::Container( std::string strName, std::string strType, const
Geometry& geometry) : Geom(geometry)
{
stdstrContainerName = strName;
stdstrPluginType = strType;
}
void TreeModel::SetContainer(const QModelIndex &index, Container Cont)
{
TreeItem *item = getItem(index);
item->setContainer(Cont);
}
class TreeItem
{
public:
// Functions here
private:
QList<TreeItem*> childItems;
Container itemData;
TreeItem* parentItem;
};
1) Is this the correct approach?
2) How can I cast the Geometry objects to the Geometry pointer?
With
Sph sphere();
You have declared a function wich return a Sphere object and take no parameters.
To declare an object to Sph you just simple write
Sph sphere; or Sph sphere{};
I guess you tried the first but it didn't compile, so you just changed the signature "until compiled".
You have declared a custom constructor, which means the compiler does not provide you anymore a default constructor so you can't declare a variable without calling the correct constructor (and in your case it wouldn't have sense).
In addition with
Geometry *geom = new Geometry;
geom = &sphere;
you're creating a new pointer geometry than leaking it immediatly and reassigning to a sphere geometry which has no sense at all.
Moreover all your method are public in Geometry and this does not have sense (why putting bool valid public and then a getter?).
in addition class Container is holding an instance to a base class which will give you issues due to object slicing, you need to use a pointer or a reference.
for just answering to your question you should instance a sphere with
Geometr* geom = new Sphere(1, 5); // random numbers
but the most genuine and honest thing I can tell is to rewrite everything from scratch and before that to study a little more trying with an easier example.
The minimal code that works and implements an idea in the question:
#include <iostream>
class Geometry
{
public:
Geometry(const std::string type) { stdstrType = type; }
std::string GetName() { return stdstrType; }
virtual void draw() {} ;
private:
std::string stdstrType;
};
class Sphere : public Geometry
{
public:
Sphere(float radius): Geometry("Sphere ") { fRadius = radius; }
virtual void draw() { std::cout << GetName() << fRadius << "\n";}
private:
float fRadius;
};
class Container
{
public:
Container(std::string strName, Geometry* g)
{
stdstrContainerName = strName;
geometry = g;
}
void draw() { geometry->draw(); }
private:
std::string stdstrContainerName;
Geometry *geometry;
};
int main(int argc, const char * argv[]) {
Sphere sphere(0.1);
Geometry *geom = &sphere;
Container cont("Sphere container", geom);
cont.draw();
return 0;
}
Xcode 10.2.1: No Buildtime/Runtime Issues. Output:
Sphere 0.1
Program ended with exit code: 0
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);
}
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).
I'm writing a simple game in SDL. I have a class heirarchy that I am constructing for any sprite I use in the game. The base class is Sprite, which contains data abstractions for the collision box and the spritesheet. Directly below that are two abstract classes, Character and MapObject.
I am currently implementing the Player class which is derived from Character (Enemy and NPC will also be derived from the abstract Character class).
Anyway, hopefully that makes sense. My problem is this:
When I try and use the player class in the engine, I cannot access any of the Sprite functions.
I get the following error:
'Sprite' is not an accessible base of 'Player'
Here are the header files:
Sprite.h:
class Sprite{
public:
virtual ~Sprite() = 0; //I want this to be an abstract class and yes this is defined in the cpp
//Initialization functions - MUST be called before anything else in the class can be used.
void setupCollider(int xo, int yo, int ho, int wo);
void setupSheet(SDL_Surface* dest, std::string file, int numClips, int ac, int _res, int sr);
//SpriteSheet functions
void setActiveClip(int a);
int getActiveClip() const;
void draw() const;
int getResolution() const;
SDL_Surface* getDest();
//Collider functions
void updateCollider();
SDL_Rect box() const;
bool collision(SDL_Rect other) const;
//Access and Modify coordinates of the sprite
void setLoc(int x, int y) { _x = x; _y = y; }
int getX() const { return _x; }
int getY() const { return _y; }
private:
struct Collider{
SDL_Rect _box;
int x_offset,
y_offset;
};
struct SpriteSheet{
SDL_Surface* destination;
SDL_Surface* sheet;
SDL_Rect* clips;
int _numClips;
int active;
int res;
int sheetrows;
};
Collider collisionAttributes;
SpriteSheet spriteSheetAttributes;
int _x, _y;
};
Character.h:
class Character : public Sprite{
public:
virtual void move(Direction direction_input, const TileMap& currentlevel) = 0;
virtual void animate() = 0;
virtual void setAttributes( int h, int sp, int ad, int d, int m, int md, int l, std::string n){
hearts = h; speed = sp; attackdamage = ad;
defense = d; magicdamage = m; magicdefense = md;
level = l; name = n;
}
bool isDead() const{
return hearts == 0;
}
void heal(int heartsup){
hearts += heartsup;
}
void dealDamage(int heartsDown){
hearts -= heartsDown;
}
protected:
int hearts;
int speed;
int attackdamage;
int defense;
int magicdamage;
int magicdefense;
int level;
std::string name;
};
Player.h:
//Not fully finished yet, but should work for the purposes of this question
class Player : protected Character{
public:
~Player(){
if(heart) SDL_FreeSurface(heart);
}
static const int HEART_WIDTH;
void move(Direction direction_input, const TileMap& currentlevel);
void animate();
void updateCamera(TileMap& currLevel);
private:
SDL_Surface* heart;
enum ClipFace
{
UP1,
UP2,
DOWN1,
DOWN2,
LEFT1,
LEFT2,
RIGHT1,
RIGHT2
};
static const std::string HEART;
static const int HEART_RES;
};
I get the first error in my engine when I try to call the setup functions from Sprite in player, the first one being:
player.setLoc(levels[0].startX(), levels[0].startY());
Any and all help is appreciated.
[SOLVED] EDIT: An alternative solution to the comments: The character class didn't inherit anything from the Sprite class, so it didn't technically have to be derived from it. Instead of having Character inherit from Sprite, I had Player inherit from BOTH Sprite and Character and that also worked. I'm not sure what is better design though.
I think you need to change
class Player : protected Character{
to
class Player : public Character{
That way you can access Character and Sprite's functions on a Player object from an instance of Player created anywhere in your program.
If a Player should be able to do anything a Character can do, public inheritance makes sense. There's no reason to hide something in Player that would be freely accessible in Character or Sprite objects.
Always use public inheritance to represent an "is-a" relationship. It sounds like Player is a Character, so that inheritance should be public, not protected.
protected inheritance and private inheritance are more like "has-a" (and in most cases, a member subobject is an easier way to deal with that relationship).
I'd bet that since Character is a protected base class, its restricting the access to Sprite.