How to instantiate abstract child class with parent class - c++

I'm trying to make a Chess game, and I'm having difficulties with creating the objects. My thought process went something like this:
Create a game board with 64 tiles, the tiles would have their own position and a pointer to a piece, thus I would be able to "easily" load in and unload a piece.
Tile class:
class Tile {
private:
int x;
int y;
Piece* piece;
public:
Tile(int x, int y) {
this->x = x;
this->y = y;
piece = nullptr;
}
void loadTile(Piece piece) {
this->piece = new Piece(piece); //this gives an error
}
void unloadTile() {
delete this->piece;
}
};
The individual pieces would then inherit from a parent class (below you can see a dumbed-down version). Inherited pieces would all have the same constructor and they would only differ in the way they calculate the possible moves. This, in my mind, is the best scenario to use a virtual function.
Piece and pawn class:
class Piece {
protected:
int x;
int y;
public:
Piece(int x, int y) {
this->x = x;
this->y = y;
}
virtual vector<int> returnPossibleMoves() = 0;
};
class Pawn : public Piece {
public:
using Piece::Piece;
vector<int> returnPossibleMoves() {
vector<int> moves;
moves.push_back(10); //dont think about this too much
return moves;
}
};
And here is the problem - the loadTile() function cannot instantiate the piece object because it is abstract.
I can see that my code may not work because I try to instantiate Piece with Pawn, but I don't really know how I would make it work, or what the workaround for this is. Hopefully you will be able to see what I'm trying to go for.

To strictly answer the question: you cannot create instances of abstract classes. That's why new Piece is not allowed. You would have to create an instance of a derived type that is not abstract, such as Pawn, and assign the piece pointer to point to that:
void Tile::loadTile() {
this->piece = new Pawn; //this is allowed
}
There are clearly some design changes that you'll need to make with this in mind, some of which have been mentioned in the comments on your question.

The Tile don't know which Piece type to instantiate, this is the fundamental problem.
What about something like this? (Disclaim, I just implemented some ideas, the code need probably lot of improvements until to get to sufficient quality)
#include <array>
#include <cassert>
#include <memory>
#include <vector>
using namespace std;
class Piece;
using CPiecePtr = std::shared_ptr<const Piece>;
enum class PieceType
{
Pawn
};
class Pos
{
int m_x=0;
int m_y=0;
public:
Pos()=default;
Pos(const Pos&)=default;
Pos& operator=(const Pos&)=default;
Pos( int x, int y): m_x(x), m_y(y)
{
assert(x>=0 && x<8 && y>=0 && y<8);
}
int x() const { return m_x; }
int y() const { return m_y; }
};
class Move
{
Pos m_origin;
Pos m_destination;
public:
Move()=default;
Move(const Move&)=default;
Move& operator=(const Move&)=default;
Move( const Pos& orig, const Pos& dest): m_origin(orig), m_destination(dest){}
const Pos& getDestination() const { return m_destination; }
const Pos& getOrigin() const { return m_origin; }
};
using MoveSet = std::vector<Move>;
class Tile
{
private:
CPiecePtr m_piece;
public:
void loadTile(CPiecePtr piece)
{
m_piece = piece;
}
void unloadTile()
{
m_piece = nullptr;
}
void setPiece(CPiecePtr piece) // this is more generic than previous two functions
{
m_piece = piece;
}
CPiecePtr getPiece() const
{
return m_piece;
}
};
class Piece
{
PieceType m_type;
public:
virtual MoveSet returnPossibleMoves(const Pos&) const = 0;
Piece(): m_type(PieceType::Pawn){}
PieceType getType() const { return m_type; }
};
class Pawn : public Piece
{
public:
MoveSet returnPossibleMoves(const Pos& pos) const override
{
MoveSet moves;
moves.push_back(Move(pos, Pos(pos.x(), pos.y()+1)));
//...
//TODO how to manage special moves? King-rook, replace pawn at end line...
return moves;
}
};
class Chess
{
private:
std::array<std::array<Tile,8>,8> m_board;
std::vector<CPiecePtr> m_pieces;
public:
Chess()
{
m_pieces.push_back( std::make_shared<const Pawn>());
//...
setPieceAt(Pos(0,1), m_pieces[0]);
}
CPiecePtr getPieceAt( const Pos& pos) const
{
return m_board[pos.x()][pos.y()].getPiece();
}
void setPieceAt( const Pos& pos, CPiecePtr piece)
{
return m_board[pos.x()][pos.y()].setPiece(piece);
}
// example:
MoveSet getMoveSetForPos( const Pos& pos)
{
const auto& piecePtr = getPieceAt(pos);
if (nullptr != piecePtr)
{
return piecePtr->returnPossibleMoves(pos);
}
return {};
}
void movePiece( const Move& move)
{
const auto& prevPiece = getPieceAt(move.getOrigin());
const auto& nextPiece = getPieceAt(move.getDestination());
assert(prevPiece && !nextPiece);
setPieceAt(move.getDestination(), prevPiece);
setPieceAt(move.getOrigin(), nullptr);
}
};
int main()
{
Chess chess;
const auto& moves = chess.getMoveSetForPos(Pos(0,1));
if (moves.size()>0)
{
chess.movePiece(moves[0]);
}
assert( chess.getPieceAt(Pos(0,2))->getType() == PieceType::Pawn);
return 0;
}
EDIT: I was not very proud of the answer, so I edited the code to make it compile. However, a fully working Chess is more complex than that, I leave how to manage king-rook and other special moves to the reader.

Related

using template classes above main giving error during function call in main

I am using a base class and a child class defined above main in main.cpp
this gives me an error of undefined reference FactoryTraversal::AddPoint::AddPoint(int const&, int const&, int)'
Here is the code:
#include <iostream>
#include <list>
#include <typeinfo>
#include <cmath>
enum traversal_type
{
TRAVERSAL = 0,
TRAVERSALMAX
};
template <class T>
class FactoryTraversal
{
public:
FactoryTraversal();
FactoryTraversal *CreateInstance(const traversal_type &type);
virtual ~FactoryTraversal();
const std::list<int>& GetIndices() const {return indices;}
int GetIndicesSize() const {return indices.size();}
virtual void AddPoint(const T &x, const T &y, int index);
protected:
std::list<int> indices;
};
template<class T>
class Traversal : public FactoryTraversal<T>
{
public:
Traversal();
void AddPoint(const T &x, const T &y, int index);
int GetResultXOR() const {return result_xor;}
private:
T coords_s[2];
T coords_e[2];
int result_xor;
void update_result(int index);
T calculate_distance(const T &x1, const T &x2, const T &y1, const T &y2);
};
template<class T>
Traversal<T>::Traversal():FactoryTraversal<T>()
{
//Do nothing
}
template<class T>
void Traversal<T>::AddPoint(const T &x, const T &y, int index)
{
if (0 == this->GetIndicesSize())
{
this->indices.push_front(index);
coords_s[0] = x; coords_s[1] = y;
coords_e[0] = x; coords_e[1] = y;
}
else
{
T d1 = this->calculate_distance(x,coords_s[0],y,coords_s[1]);
T d2 = this->calculate_distance(x,coords_e[0],y,coords_e[1]);
if (d1 < d2)
{
this->indices.push_front(index);
coords_s[0] = x; coords_s[1] = y;
}
else
{
this->indices.push_back(index);
coords_e[0] = x; coords_e[1] = y;
}
}
this->update_result(index);
}
template<class T>
T Traversal<T>::calculate_distance(const T &x1, const T &x2, const T &y1, const T &y2)
{
if (typeid(T) == typeid(int))
{
return std::min(std::abs(x1-x2),std::abs(y1-y2));
}
return 0;
}
template<class T>
void Traversal<T>::update_result(int index)
{
if (0 == this->GetIndicesSize())
result_xor = index;
else
result_xor ^= index;
}
template<class T>
FactoryTraversal<T>::FactoryTraversal()
{
indices.clear();
}
template<class T>
FactoryTraversal<T>::~FactoryTraversal()
{
//Do Nothing
}
template<class T>
FactoryTraversal<T>* FactoryTraversal<T>::CreateInstance(const traversal_type &type)
{
if (TRAVERSAL == type)
return new Traversal<T>();
else
return NULL;
}
FactoryTraversal<int> factory_traversal;
Traversal<int> *traversal = new Traversal<int>();
int main()
{
int T;
std::cin>>T;
int output[T];
for (int i = 0; i < T; ++i)
{
int N;
std::cin>>N;
FactoryTraversal<int> factory_traversal;
FactoryTraversal<int> *traversal = factory_traversal.CreateInstance(TRAVERSAL);
for (int j = 0; j < N; ++j)
{
int x, y;
std::cin>>x>>y;
traversal->AddPoint(x,y,j+1);
}
Traversal<int> *tmp = dynamic_cast<Traversal<int> *>(traversal);
if (tmp)
output[i] = tmp->GetResultXOR();
else
output[i] = 0;
}
for (int i = 0; i < T; ++i)
{
std::cout<<output[i]<<std::endl;
}
return 0;
}
Interfaces in C++ are called "abstract classes", and classes are abstract if they have at least one "pure virtual function". A function is a pure virtual function if it is prefixed with virtual and has a trailing =0 in its declaration. This is what you want for FactoryTraversal::AddPoint:
virtual void AddPoint(const T &x, const T &y, int index) = 0;
Now the derived class is expected to define it (and it does). Without AddPoint being pure virtual, you are forced to provide an implementation for it in the base class, which you could do simply as:
virtual void AddPoint(const T &x, const T &y, int index){}
This gives a "default" or fallback implementation for when a derived class chooses not to override the method. If it were pure virtual, the derived class is forced to define it, lest a call to it result in a compiler error (otherwise the derived class is also considered abstract).
Note that destructors should never be pure virtual. The way you have it right now is great; you unconsciously followed the rules I've outlined above.
Some other notes:
Variable length arrays are not legal C++, this is a compiler extension:
int output[T]; // T is read from command line
Use a vector instead:
std::vector<int> output(T);
You have memory leaks as-is. Use a managed pointer like unique_ptr so you don't have to worry about new and delete
I stated that you wanted AddPoint to be pure virtual and I mean it. You code won't compile if that's the first step you take, though. It looks like you merged a base class and a factory into one; split those out.
Putting it all together we can define our new base class as:
template<class T>
class TraversalBase
{
public:
virtual ~TraversalBase(){}
const std::list<int>& GetIndices() const {return indices;}
int GetIndicesSize() const {return indices.size();}
virtual void AddPoint(const T &x, const T &y, int index) = 0;
protected:
std::list<int> indices;
};
The derived class becomes (very little change, also notice the override keyword):
template<class T>
class Traversal : public TraversalBase<T>
{
public:
void AddPoint(const T &x, const T &y, int index) override;
int GetResultXOR() const {return result_xor;}
private:
T coords_s[2];
T coords_e[2];
int result_xor;
void update_result(int index);
T calculate_distance(const T &x1, const T &x2, const T &y1, const T &y2);
};
And our Factory class is much simplified:
template <class T>
struct FactoryTraversal
{
FactoryTraversal(){}
std::unique_ptr<TraversalBase<T>> CreateInstance(const traversal_type &type);
~FactoryTraversal(){}
};
Live Demo (C++11)

upcasting variable in derived class c++

How to change the type of a inherited variable in the derived class?
I have the following classes:
class Position;
class StonePosition;
class Position {
public:
Position() {}
};
class StonePosition : public Position {
int count;
public:
StonePosition(const int count) { this->count = count; }
int getCount() { return this->count; }
void setCount(int count) { this->count = count; }
friend ostream& operator<<(ostream&, StonePosition);
};
class Board {
protected:
Position* crrPos;
public:
Board() { }
Position* getCrrPos() { return crrPos; }
void setCrrPos(Position* pos) { crrPos=pos; }
};
class StoneBoard : public Board {
public:
StoneBoard(const int &count) { this->crrPos=new StonePosition(count); } //<----------------
StonePosition* getCrrPos() { return (StonePosition*)crrPos; }
void setCrrPos(StonePosition* pos) { crrPos=pos; }
};
Place in which the problem is marked by an arrow. I need to change the type of a variable from Position to StonePosition in the StoneBoard class. I found an option that can be used upcasting, but it works only within a single method, and I need to change the variable for the entire class.
The problem was solved, look at my answer.
The variable "crrPos" is not of type Position it is of type pointer to Position and this is significant because a pointer to Position can point to a Position or a class derived from Position without losing anything.
If you design your classes well, and make use of virtual functions, you can usually avoid the need to upcast entirely.
#include <iostream>
class Base {
public:
virtual void foo() { std::cout << "Base::foo()\n"; }
virtual bool isDerived() const { return false; }
};
class Derived : public Base {
public:
void foo() override { std::cout << "Derived::foo()\n"; }
bool isDerived() const { return true; }
};
int main() {
Base* crrPos = new Derived;
crrPos->foo();
bool isDerived = crrPos->isDerived();
std::cout << isDerived << '\n';
delete crrPos;
}
Live demo: http://ideone.com/UKcBaA
The problem has been solved, I just use the projection ((StonePosition*)Position*):
#include <iostream>
using namespace std;
class Position;
class StonePosition;
class Position {
public:
Position() {}
};
class StonePosition : public Position {
int count;
public:
StonePosition(const int count) { this->count = count; }
int getCount() { return this->count; }
void setCount(int count) { this->count = count; }
friend ostream& operator<<(ostream&, StonePosition);
};
template <typename TPos> class TBoard {
protected:
TPos* crrPos;
public:
TBoard() { }
TPos* getCrrPos() { return crrPos; }
void setCrrPos(TPos* pos) { crrPos=pos; }
};
class Board {
protected:
Position* crrPos;
public:
Board() { }
Position* getCrrPos() { return crrPos; }
void setCrrPos(Position* pos) { crrPos=pos; }
};
class StoneBoard : public Board {
public:
StoneBoard(const int &count) { this->crrPos=new StonePosition(count); }
Position* getCrrPos() { return crrPos; }
void setCrrPos(Position* pos) { crrPos=pos; }
};
int main(){
StoneBoard s(7);
cout<<((StonePosition*)s.getCrrPos())->getCount();//<----right here
system("pause");
return 0;
}
And its working nice :)

Class factory to create derived classes c++

I'm currently learning about class factory patterns with C++. I keep having errors while trying to implement the factory. Suppose I have an abstract class and two derived classes. What I want the factory to do is to create a new object of the base class like so: Ball *sc = new SoccerBall();
I am not sure on how to implement this, I have tried but of no avail. What do I need to fix?
class Ball
{
public:
Ball();
virtual ~Ball();
virtual int getSize() const = 0;
virtual void setBallSize(int s) = 0;
virtual string ballManufacturer() const = 0;
protected:
int ballSize;
}
class Soccerball:public Ball
{
public:
Soccerball();
Soccerball(int size);
~Soccerball();
int getSize() const;
void setBallSize(int s);
string ballManufacturer() const;
}
class Soccerball:public Ball
{
public:
Soccerball();
Soccerball(int size);
~Soccerball();
int getSize() const;
void setBallSize(int s);
string ballManufacturer() const;
}
class Basketball:public Ball
{
public:
Basketball();
Basketball(int size);
~Basketball();
int getSize() const;
void setBallSize(int s);
string ballManufacturer() const;
}
class BallFactory
{
public:
Ball* createBall(string s)
{
if(s == "Soccer")
{
return new Soccerball(5);
}
if(s == "Basket")
{
return new Basketball(6);
}
}
}
This how your code will work, but above when you are posting a question you should provide "Short Self Contained Correct Code" and make easy for people to understand your problem easily.
#include <iostream>
using namespace std;
class Ball
{
public:
Ball()
{
cout<<"Ball ctr"<<endl;
}
virtual ~Ball()
{
}
virtual int getSize() const = 0;
virtual void setBallSize(int s) = 0;
virtual string ballManufacturer() const = 0;
protected:
int ballSize;
};
class Soccerball:public Ball
{
public:
Soccerball()
{
cout<<"create Default Soccer Ball "<<endl;
}
Soccerball(int size)
{
cout<<"create Soccer Ball "<<size<<endl;
}
~Soccerball()
{
}
int getSize() const
{
return ballSize;
}
void setBallSize(int s)
{
ballSize = s;
}
string ballManufacturer() const
{
return "";
}
};
class Basketball:public Ball
{
public:
Basketball()
{
cout<<"create default Baseket Ball "<<endl;
}
Basketball(int size)
{
cout<<"create Baseket Ball "<<size<<endl;
}
~Basketball()
{
}
int getSize() const
{
return ballSize;
}
void setBallSize(int s)
{
ballSize = s;
}
string ballManufacturer() const
{
return "";
}
};
class BallFactory
{
public:
//Factory method
static Ball* createBall(string s)
{
if(s == "Soccer")
{
return new Soccerball(5);
}
if(s == "Basket")
{
return new Basketball(6);
}
}
};
int main()
{
Ball* ptr = BallFactory::createBall("Soccer");
return 0;
}
But you also need to understand how Factory design pattern works and how a namesake virtual constructor is created and why you would use a parameterized factory. Or could you use a template factory.

c++ Singleton with map cause "violation reading location"

I was trying to create a singleton to access a global-like class. This class work perfectly except when I use the std::map inside.
(yes i know, putting methods in .h..., but it's for debugging):
panthera.h
class Panthera
{
private:
std::map<std::string, std::map<long, Object *>> entities;
public:
Panthera(void);
~Panthera(void);
static Panthera * GetInstance()
{
static Panthera *engine_ = new Panthera();
return engine_;
}
void Run() {std::cout << "I run" << std::endl;}
void DOESNOTWORK(Object *o) {this->entities["test"][0] = o;}
};
main.cpp
Panthera::GetInstance()->Run(); // no problem
Panthera::GetInstance()->DOESNOTWORK(); // access violation
Been trying to solve this for some time now... Any leads?
After looking into things with OneonOne i understood that the problem was the class Object (it work if I replace it by anempty class)
tried to look in this class for incoherency/other but can't find the root of the problem, so here is the class
Object.h
#pragma once
#include "Vector2.h"
#include <list>
class Object
{
protected:
Vector2 location;
float rotation;
std::string plane;
unsigned long id;
std::list<Object *> children;
public:
Object(void);
Object(Vector2 const & location, std::string const & plane = "background", float rotation = 0);
Object(Object const & other);
~Object(void);
public:
virtual void SetLocation(Vector2 const & location);
virtual Vector2 GetLocation() const;
virtual void SetRotation(float);
virtual float GetRotation() const;
virtual void Move(Vector2 const & displacement);
virtual void Rotate(float angle);
virtual void Adopt(Object * other, Vector2 const & mountPoint = Vector2());
virtual Vector2 Mount(Vector2 const & other) const;
std::string GetPlane() const;
long GetId() const;
};
the implementation is trivial, and the class in itself run fine EXCEPT when it is added in a std::map and this only from a singleton...
As usual, thank you in advance for any help (and ask if you need the source file (or the Vector2 class))
As requested, the Object.cpp file
#include "Object.h"
#include "Matrix.h"
#include "Panthera.h"
Object::Object(void): location(Vector2()), rotation(0), plane("background")
{
this->id = reinterpret_cast<long>(this);
Panthera::GetInstance()->DOESNOTWORK(this);
}
Object::Object(Vector2 const & location, std::string const & plane, float rotation): location(location), rotation(rotation), plane(plane)
{
this->id = reinterpret_cast<long>(this);
//Panthera::GetInstance().Add(this);
}
Object::Object(Object const & other)
{
*this = other;
this->id = reinterpret_cast<long>(this);
// Panthera::GetInstance().Add(this);
}
Object::~Object(void)
{
}
void Object::SetLocation(Vector2 const & location)
{
this->Move(location - this->location);
}
Vector2 Object::GetLocation() const
{
return this->location;
}
void Object::SetRotation(float rotation)
{
this->Rotate(rotation - this->rotation);
}
float Object::GetRotation() const
{
return this->rotation;
}
void Object::Move(Vector2 const & displacement)
{
std::list<Object *>::iterator it;
for (it = this->children.begin() ; it != this->children.end(); ++it)
{
(*it)->Move(displacement);
}
this->location += displacement;
}
void Object::Rotate(float angle)
{
std::list<Object *>::iterator it;
for (it = this->children.begin() ; it != this->children.end(); ++it)
{
(*it)->SetLocation(Matrix::Transform((*it)->GetLocation() - this->location, angle) + this->location);
}
this->rotation += angle;
}
void Object::Adopt(Object * other, Vector2 const & mountpoint)
{
other->SetLocation(this->Mount(Matrix::Transform(mountpoint, this->rotation)));
this->children.push_back(other);
}
Vector2 Object::Mount(Vector2 const & other) const
{
return Vector2(this->location + other);
}
std::string Object::GetPlane() const
{
return this->plane;
}
long Object::GetId() const
{
return this->id;
}
Update: just calling the constructor of Object fails. for some reason it doesn't let me use the singleton in his constructor, => this is the root of the problem
Resolved: the problem was having a Object in the singleton class, the Object constructor made use of the singleton before it was initialized.
Your code doesn't even compile because your Constructor and Destruct weren't implemented.
Here's a C++11 version :
#include <unordered_map>
#include <iostream>
#include <string>
class Object {};
class Panthera {
private:
std::unordered_map<std::string, std::unordered_map<long, Object *>> entities;
Panthera() noexcept {}
public:
static Panthera & GetInstance() noexcept {
static Panthera engine_;
return engine_;
}
void Run() {std::cout << "I run" << std::endl;}
void worksnow() {this->entities["test"][0] = new Object;}
void get_test() {
std::cout << this->entities["test"].size() << std::endl;
}
};
int main() {
Panthera::GetInstance().Run(); // no problem
Panthera::GetInstance().worksnow(); //works too
Panthera::GetInstance().get_test();
return 0;
}
Test :
|---> clang++ -std=c++11 -stdlib=libc++ -lc++abi -I. test-singleton.cpp && ./a.out
I run
1
The original code works fine for me, so your problem is compiler related or with the omitted code :
#include <iostream>
#include <string>
#include <map>
class Object {};
class Panthera {
private:
std::map<std::string, std::map<long, Object *> > entities;
public:
Panthera(void) {}
~Panthera(void) {}
static Panthera * GetInstance() {
static Panthera *engine_ = new Panthera();
return engine_;
}
void Run() {std::cout << "I run" << std::endl;}
void DOESNOTWORK() {
this->entities["test"][0] = new Object;
std::cout << this->entities["test"].size() << std::endl;
}
};
int main() {
Panthera::GetInstance()->Run(); // no problem
Panthera::GetInstance()->DOESNOTWORK(); // access violation
return 0;
}

Reference in place of getters?

in C++ is it a bad practice to use reference in place of getters?
for example:
class X
{
int mP;
public:
const int& P;
X():P(mP){}
};
and later
X xl;
int h = xl.P;
Just think about refactoring to make the access thread safe, that won't work well this way and require a lot of changes in the client classes/functions.
If you have class members, that are guaranteed not to be changed over lifetime of the instance, you can simply provide const int P; and initialize it properly in your class' constructors.
If the value is to be visible class wide use a static const int P;
In any other case use a public getter:
int P() const; // a return type of 'const int &' would be redundant
1st shot implementation:
int X::P() const
{
return mP;
}
Thread safe implementation:
class X {
{
// ...
private:
// ...
mutable std::mutex internalDataGuard;
};
int X::P() const
{
std::lock(internalDataGuard);
return mP;
}
None of this is good:
class X { public: int x; };
class X {
private: int m_x;
public: const int& get() const { return m_x; }
public: void set(const int& other) { m_x = other; }
};
class X {
private: int m_x;
public: const int& x() const { return m_x; }
public: void x(const int& other) { m_x = other; }
};
class X {
private: int m_x;
public: const int& x() const { return m_x; }
public: int& x() { return m_x; }
};
Pick one, it's a design decision.
Having 'const int& x' to publish the private member will work:
class X {
private: int m_x;
public: const int& x;
public: X() : m_x(0), x(m_x) {}
// Take care for copy and assignment
};
The cost is a larger memory footprint.