I was trying to follow the SFML Blueprint book. I managed to remove all the errors but one error remains in the code.
I have tried to find about the debug-assertion-failed.
I think this issue is arising due to the lists one of them is getting emptied.
My code for the world.cpp
#include "World.h"
#include "Entity.h"
World::World(int x, int y) : _x(x), _y(y) {}
World::~World() { clear(); }
void World::add(Entity* entity){
_entities_tmp.push_back(entity);
}
void World::clear()
{
for (Entity* entity : _entities)
delete entity;
_entities.clear();
for (Entity* entity : _entities_tmp)
delete entity;
_entities_tmp.clear();
_sounds.clear();
}
void World::add(Configuration::Sounds sound_id){
std::unique_ptr<sf::Sound> sound(new sf::Sound(Configuration::sounds.get(sound_id)));
sound->setAttenuation(0);
sound->play();
_sounds.emplace_back(std::move(sound));
}
bool World::isCollide(const Entity& other)
{
for (Entity* entity_ptr : _entities)
if (other.isCollide(*entity_ptr))
return true;
return false;
}
int World::size() {
return _entities.size() + _entities_tmp.size();
}
int World::getX() const{
return _x;
}
int World::getY() const{
return _y;
}
const std::list<Entity*> World::getEntities() const {
return _entities;
}
void World::update(sf::Time deltaTime)
{
if (_entities_tmp.size() > 0)
_entities.merge(_entities_tmp);
for (Entity* entity_ptr : _entities)
{
Entity& entity = *entity_ptr;
entity.update(deltaTime);
sf::Vector2f pos = entity.getPosition();
if (pos.x < 0)
{
pos.x = _x;
pos.y = _y - pos.y;
}
else if (pos.x > _x)
{
pos.x = 0;
pos.y = _y - pos.y;
}
if (pos.y < 0)
pos.y = _y;
else if (pos.y > _y)
pos.y = 0;
entity.setPosition(pos);
}
const auto end = _entities.end();
for (auto it_i = _entities.begin(); it_i != end; ++it_i)
{
Entity& entity_i = **it_i;
auto it_j = it_i;
it_j++;
for (; it_j != end; ++it_j)
{
Entity& entity_j = **it_j;
if (entity_i.isAlive() && entity_i.isCollide(entity_j))
entity_i.onDestroy();
if (entity_j.isAlive() && entity_j.isCollide(entity_i))
entity_j.onDestroy();
}
}
for (auto it = _entities.begin(); it != _entities.end();)
{
if (!(*it)->isAlive()){
delete *it;
it = _entities.erase(it);
}
else ++it;
}
_sounds.remove_if([](const std::unique_ptr<sf::Sound>& sound)->
bool {
return sound->getStatus() != sf::SoundSource::Status::Playing;
});
}
void World::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
for (Entity* entity : _entities)
target.draw(*entity, states);
}
Code for world.hpp
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <list>
#include <memory>
#include "Configuration.h"
class Entity;
class World : public sf :: Drawable
{
public:
World(const World&) = delete;
World& operator=(const World&) = delete;
World(int x, int y);
~World();
void add(Entity* entity);
void clear();
bool isCollide(const Entity& other);
int size();
void add(Configuration::Sounds sound_id);
const std::list<Entity*> getEntities() const;
int getX() const;
int getY() const;
void update(sf::Time deltaTime);
private:
std::list<Entity*> _entities;
std::list<Entity*> _entities_tmp;
std::list<std::unique_ptr<sf::Sound>> _sounds;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
const int _x;
const int _y;
};
code for Entity.h
class World;
class Entity : public sf::Drawable
{
public:
//Constructors
Entity(const Entity&) = delete;
Entity& operator= (const Entity&) = delete;
Entity(Configuration::Textures tex_id, World& world);
virtual ~Entity();
//Helpers
virtual bool isAlive() const;
const sf::Vector2f& getPosition() const;
template<typename ... Args>
void setPosition(Args&& ... args);
virtual bool isCollide(const Entity& other) const = 0;
//Updates
virtual void update(sf::Time deltaTime) = 0;
virtual void onDestroy();
protected:
friend class Meteor;
friend class Player;
friend class Saucer;
friend class ShootPlayer;
friend class ShootSaucer;
sf::Sprite _sprite;
sf::Vector2f _impulse;
World& _world;
bool _alive;
private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;
};
if (_entities_tmp.size() > 0)
_entities.merge(_entities_tmp);
This does not work. merge works with two sorted ranges. And your vector is not sorted. This is why you get an assertion.
If not sorting them is on purpose and you just want to concatenate the two vectors, you can do:
_entities.reserve( _entities.size() + _entities_tmp.size() );
_entities.insert( _entities.end(), _entities_tmp.begin(), _entities_tmp.end() );
Related
I'm trying to implement a graph using adjacency list, but in the A_List class function called ,,AddGraphEdge" , there's a problem ,,Exception thrown: read access violation.this was 0x20." It occurs in the list.cpp function ,,AddEdge" when I do if(head==nullptr). I just simply check if head is null. When i delete this statement in place when I assign head=new_edge it tells me the same problem. It works fine if I'm using only normal list, and i create an list object in main and call AddEdge function. I don't know why calling this function in another causes problems.
Graph.h
class Graph
{
protected:
int _Vertices;
int _Edges;
int _Density;
public:
Graph() : _Vertices(0), _Edges(0), _Density(0) {};
Graph(const int& Vertices,const int& Edges, const int& Density) : _Vertices(Vertices), _Density(Density), _Edges(Edges) {};
void set_Vertices(const int& Vertices) { _Vertices=Vertices; };
int get_Vertices() { return _Vertices; };
void set_Edges(const int& Edges) { _Edges=Edges; };
int get_Edges() { return _Edges; };
virtual void DisplayGraph() = 0;
virtual void Get_Random_Graph() = 0;
};
Edge.h
class Edge
{
private:
int _StartVertice;
int _EndVertice;
int _weight;
Edge* _NextEdge;
public:
Edge():_StartVertice(0), _EndVertice(0), _weight(0), _NextEdge(nullptr) {};
Edge(const int& StartVertice, const int& EndVertice, const int& weight) : _StartVertice(StartVertice), _EndVertice(EndVertice), _weight(weight), _NextEdge(nullptr) {};
const int& get_StartVertice() const { return _StartVertice; };
const int& get_EndVertice() const { return _EndVertice; };
const int& get_Weight() const { return _weight; };
Edge* get_NextEdge() { return _NextEdge; };
void set_NextEdge(Edge* NextEdge) { _NextEdge = new Edge; _NextEdge = NextEdge; };
void set_EdgeValues(const int& StartVertice, const int& EndVertice, const int& weight)
{
_StartVertice = StartVertice;
_EndVertice = EndVertice;
_weight = weight;
};
};
List.h
#include "Edge.h"
class List
{
private:
int ListSize;
Edge* head;
public:
~List() {};
List() : ListSize(0), head(nullptr) {};
const Edge* get_head() { return head; };
const int get_ListSize() { return ListSize; };
void AddEdge(const int& StartVertice, const int& EndVertice, const int& weigth);
void DisplayList();
};
Adjacency_List.h
#include "List.h"
#include "Graph.h"
class A_List: public Graph
{
private:
List* _Adj_List;
public:
A_List() : Graph() { _Adj_List = nullptr; };
A_List(const int& Vertices, const int& Edges, const int& Density) : Graph(Vertices, Edges, Density) { _Adj_List = new List[Vertices]; };
virtual void DisplayGraph() override;
virtual void Get_Random_Graph() override;
void AddGraphEdge(const int& StartVertice, const int& EndVertice, const int& weigth);
};
List.cpp
#include "List.h"
#include <iostream>
void List::AddEdge(const int& StartVertice, const int& EndVertice, const int& weigth)
{
Edge* new_edge = new Edge;
new_edge->set_EdgeValues(StartVertice, EndVertice, weigth);
if (head == nullptr)
{
head = new_edge;
}
else
{
Edge* tmp = head;
head = new_edge;
new_edge->set_NextEdge(tmp);
}
ListSize++;
}
void List::DisplayList()
{
Edge* tmp = head;
while (head->get_NextEdge() != nullptr)
{
std::cout << tmp->get_StartVertice() << tmp->get_Weight() << tmp->get_EndVertice() << std::endl;
tmp = tmp->get_NextEdge();
}
std::cout << tmp->get_StartVertice() << tmp->get_Weight() << tmp->get_EndVertice() << std::endl;
}
Adjacency_List.cpp
#include "Adjacency_List.h"
void A_List::AddGraphEdge(const int& StartVertice, const int& EndVertice, const int& weigth)
{
_Adj_List[StartVertice].AddEdge(StartVertice, EndVertice, weigth);
}
void A_List::DisplayGraph()
{int Vertices = A_List::get_Edges();
for (int i = 0; i < Vertices; i++)
{
_Adj_List[i].DisplayList();
}
}
void A_List::Get_Random_Graph()
{
}
main.cpp
#include <iostream>
#include "Adjacency_List"
int main()
{
A_List Graph_list;
Graph_list.AddGraphEdge(4,3,2);
Graph_list.DisplayGraph();
return 0;
}
The constructor sets _Adj_List to nullptr:
A_List() : Graph() { _Adj_List = nullptr; };
And now it gets dereferenced and used (it's still nullptr):
void A_List::AddGraphEdge(const int& StartVertice, const int& EndVertice, const int& weigth)
{
_Adj_List[StartVertice].AddEdge(StartVertice, EndVertice, weigth);
}
But it might not be the only bug, as it's quite messy code
So I have this scene graph for a visual studio project where me and a group of people are working on a game concept. I'm fairly new to this so any suggestions is greatly appreciated.
here is the header file for the scene graph:
#include "Category.hpp" //4
#include <SFML/System/NonCopyable.hpp> //5
#include <SFML/Graphics/Transformable.hpp> //6
#include <SFML/Graphics/Drawable.hpp> //7
#include <vector> //8
#include <set> //9
#include <memory> //10
#include <utility> //11
struct Command; //17
class CommandQueue; /18
class SceneNode : public sf::Transformable, public sf::Drawable, private sf::NonCopyable //20
{
public: //22
typedef std::unique_ptr<SceneNode> Ptr; //23
typedef std::pair<SceneNode*, SceneNode*> Pair; //24
public: //27
explicit SceneNode(Category::Type category = Category::None); //28
void attachChild(Ptr child); //30
Ptr detachChild(const SceneNode& node); //31
void update(sf::Time dt, CommandQueue& commands); //33
sf::Vector2f getWorldPosition() const; //35
sf::Transform getWorldTransform() const; //36
void onCommand(const Command& command, sf::Time dt); //38
virtual unsigned int getCategory() const; //39
void checkSceneCollision(SceneNode& sceneGraph, std::set<Pair>& collisionPairs); //41
void checkNodeCollision(SceneNode& node, std::set<Pair>& collisionPairs); //42
void removeWrecks(); //43
virtual sf::FloatRect getBoundingRect() const; //44
virtual bool isMarkedForRemoval() const; //45
virtual bool isDestroyed() const; //46
private: //49
virtual void updateCurrent(sf::Time dt, CommandQueue& commands); //50
void updateChildren(sf::Time dt, CommandQueue& commands); //51
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const; //53
virtual void drawCurrent(sf::RenderTarget& target, sf::RenderStates states) const; //54
void drawChildren(sf::RenderTarget& target, sf::RenderStates states) const; //55
void drawBoundingRect(sf::RenderTarget& target, sf::RenderStates states) const; //56
private: //59
std::vector<Ptr> mChildren; //60
SceneNode* mParent; //61
Category::Type mDefaultCategory; //62
};
bool collision(const SceneNode& lhs, const SceneNode& rhs); //65
float distance(const SceneNode& lhs, const SceneNode& rhs); //66
////.cpp file
#include "Scene Graph.h" //1
#include <SFML/Graphics/RectangleShape.hpp> //2
#include <SFML/Graphics/RenderTarget.hpp> //3
#include <algorithm> //6
#include <cassert> //7
#include <cmath> //8
SceneNode::SceneNode(Category::Type category) //11
: mChildren() //12
, mParent(nullptr) //13
, mDefaultCategory(category) //14
{ //15
} //17
void SceneNode::attachChild(Ptr child) //19
{
child->mParent = this; //21
mChildren.push_back(std::move(child)); //22
}
SceneNode::Ptr SceneNode::detachChild(const SceneNode& node) //25
{
auto found = std::find_if(mChildren.begin(), mChildren.end(), [&](Ptr& p) { return p.get() == &node; }); //27
assert(found != mChildren.end()); //28
Ptr result = std::move(*found); //30
result->mParent = nullptr; //31
mChildren.erase(found); //32
return result; //33
}
void SceneNode::updateCurrent(sf::Time dt, CommandQueue& commands) //36
{
updateCurrent(dt, commands); //38
updateChildren(dt, commands); //39
}
void SceneNode::updateCurrent(sf::Time, CommandQueue&) //42
{
//do nothing by default //44
}
void SceneNode::updateChildren(sf::Time dt, CommandQueue& commands) //47
{
for(Ptr& child : mChildren) //50
child->update(dt, commands); //51
}
void SceneNode::draw(sf::RenderTarget& target, sf::RenderStates states) const //54
{
//apply transform of current node //56
states.transform *= getTransform(); /57
//Draw node and children with changed transform //59
drawCurrent(target, states); //60
drawChildren(target, states); //61
}
void SceneNode::drawCurrent(sf::RenderTarget&, sf::RenderStates) const //66
{
//do nothing by default //68
}
void SceneNode::drawChildren(sf::RenderTarget& target, sf::RenderStates states) const //71
{
for(const Ptr& child : mChildren) //73
child->draw(target, states); //74
}
void SceneNode::drawBoundingRect(sf::RenderTarget& target, sf::RenderStates) const //77
{
sf::FloatRect rect = getBoundingRect(); //79
sf::RectangleShape shape; //80
shape.setPosition(sf::Vector2f(rect.left, rect.top)); //81
shape.setSize(sf::Vector2f(rect.width, rect.height)); //82
shape.setFillColor(sf::Color::Transparent); //83
shape.setOutlineColor(sf::Color::Green); //84
shape.setOutlineThickness(1.f); //85
target.draw(shape); //86
}
sf::Vector2f SceneNode::getWorldPosition() const //89
{
return getWorldTransform() * sf::Vector2f(); //91
}
sf::Transform SceneNode::getWorldTransform() const //94
{
sf::Transform transform = sf::Transform::Identity; //96
for (const SceneNode* node = this; node != nullptr; node = node->mParent) //98
transform = node->getTransform() * transform; //99
return transform; //101
}
void SceneNode::onCommand(const Command& command, sf::Time dt) //104
{
//command current node, if category matches //106
if (command.category & getCategory()) //107
command.action(*this, dt); //108
//command children //110
for(Ptr& child : mChildren) //111
child->onCommand(command, dt); //112
}
unsigned int SceneNode::getCategory() const //115
{
return mDefaultCategory; //117
}
void SceneNode::checkSceneCollision(SceneNode& sceneGraph, std::set<Pair>& collisionPairs) //120
{
checkNodeCollision(sceneGraph, collisionPairs); //122
for(Ptr& child : sceneGraph.mChildren) //124
checkSceneCollision(*child, collisionPairs); //125
}
void SceneNode::checkNodeCollision(SceneNode& node, std::set<Pair>& collisionPairs) //128
{
if (this != &node && collision(*this, node) && !isDestroyed() && !node.isDestroyed()) //130
collisionPairs.insert(std::minmax(this, &node)); //131
for(Ptr& child : mChildren) //133
child->checkNodeCollision(node, collisionPairs); //134
}
void SceneNode::removeWrecks() //137
{
// Remove all children which request so //139
auto wreckfieldBegin = std::remove_if(mChildren.begin(), mChildren.end(), std::mem_fn(&SceneNode::isMarkedForRemoval)); //140
mChildren.erase(wreckfieldBegin, mChildren.end()); //141
// Call function recursively for all remaining children //143
std::for_each(mChildren.begin(), mChildren.end(), std::mem_fn(&SceneNode::removeWrecks)); //144
}
sf::FloatRect SceneNode::getBoundingRect() const //147
{
return sf::FloatRect(); //149
}
bool SceneNode::isMarkedForRemoval() const //152
{
// By default, remove node if entity is destroyed //154
return isDestroyed(); //155
}
bool SceneNode::isDestroyed() const //158
{
// By default, scene node needn't be removed //160
return false; //161
}
bool collision(const SceneNode& lhs, const SceneNode& rhs) //164
{
return lhs.getBoundingRect().intersects(rhs.getBoundingRect()); //166
}
float distance(const SceneNode& lhs, const SceneNode& rhs) //169
{
return length(lhs.getWorldPosition() - rhs.getWorldPosition()); //171
}
The errors I'm getting are listed as the following:
1)Incomplete type is not allowed .cpp line 107, 108
2) namespace std has no member "mem_fn" .cpp line 140, 144
3)Identifier "length" not found .cpp line 171
4) use of undefined type "Command" .cpp line 108, 109
It looks like you don't have the <functional> header included for definition of std::mem_fn and although I see a forward declaration of Command in your scene graph header file there does not seem to be an include directive for the header file that defines Command.
I have a problem that arised with another question I made. I am using a list of pointers of a custom class (class that I have implemented), and the program crashes when I call this method, however, if I do not use a pointer list, it works fine. This is the function where the program crashes:
void enemy_spawner()
{
Point2D enemy_pos = Point2D(rand() % (SCREEN_WIDTH - 20) + 20, -20);
Point2D enemy_vel = Point2D(0, rand() % 4 + 1);
Sprite* enemy = new Sprite(enemy_pos, enemy_vel, enemy_image, enemy_info);
//Kamikaze* enemy = new Kamikaze(enemy_pos, enemy_vel, 0, enemy_image, enemy_info);
if (enemy_group.size() < MAX_ENEMIES)
{
// Program crashes here
enemy_group.push_back(enemy);
}
}
The enemy_group is a global variable defined as follows:
std::list<Sprite*> enemy_group;
My Sprite class is as follows (I have read that I need to have properly defined copy constructors, etc)
class Sprite
{
private:
Point2D sp_pos;
Point2D sp_vel;
SDL_Surface* sp_img;
Point2D sp_center;
Point2D sp_size;
double sp_radius;
bool sp_animated;
int sp_frames;
int sp_cur_frame;
public:
Sprite() {}
Sprite(Point2D pos, Point2D vel, SDL_Surface *img, ImageInfo info, bool animated = false, int frames = 0);
virtual void draw(SDL_Surface* screen);
virtual void update();
void setInfo (ImageInfo info);
void setPos( Point2D pos ) { sp_pos = pos; }
void setVel( Point2D vel ) { sp_vel = vel; }
void setImg (SDL_Surface* img) { sp_img = img; }
void setNextFrame() { sp_cur_frame++; }
void setFrame( int frame ) { sp_cur_frame = frame; }
void setAnimated(bool animated) { sp_animated = animated; }
void changeVelX (int c) { sp_vel.setX(c);}
void changeVelY (int c) { sp_vel.setY(c);}
void changePosX (int c) { sp_pos.setX(c);}
void changePosY (int c) { sp_pos.setY(c);}
SDL_Surface* getImg() { return sp_img; }
Point2D getPos() { return sp_pos; }
Point2D getVel() { return sp_vel; }
Point2D getCenter() { return sp_center; }
Point2D getSize() { return sp_size; }
double getRadius() { return sp_radius; }
int getCurFrame() { return sp_cur_frame; }
int getFrames() { return sp_frames; }
bool collide(Sprite &another_sprite);
virtual ~Sprite() {}
Sprite& operator=(Sprite other) {
std::swap(sp_pos, other.sp_pos);
std::swap(sp_vel, other.sp_vel);
std::swap(sp_img, other.sp_img);
std::swap(sp_center, other.sp_center);
std::swap(sp_size, other.sp_size);
std::swap(sp_radius, other.sp_radius);
std::swap(sp_animated, other.sp_animated);
std::swap(sp_frames, other.sp_frames);
std::swap(sp_cur_frame, other.sp_cur_frame);
return *this;
}
Sprite(const Sprite &obj)
{
sp_pos = obj.sp_pos;
sp_vel = obj.sp_vel;
sp_img = new SDL_Surface;
*sp_img = *obj.sp_img;
sp_center = obj.sp_center;
sp_size = obj.sp_size;
sp_radius = obj.sp_radius;
sp_animated = obj.sp_animated;
sp_frames = obj.sp_frames;
sp_cur_frame = obj.sp_cur_frame;
}
};
If it matters, I am using gcc compiler (Actually my IDE is codeblocks). The question is, why does the program crash? How do I solve this issue?
Thanks in advance
I'm trying to code a game with Allegro 4 and I've hit a weird bump. The linker is claiming an undefined reference to the destructor in two of my classes, but I've done nothing with it. What could be the issue? Here is my code:
Entity.h:
#pragma once
#include <allegro.h>
struct Rectangle
{
int x;
int y;
int w;
int h;
};
typedef enum {
FACE,
POOP
} EntityType;
class Entity
{
private:
EntityType m_EntityType;
BITMAP *m_Sprite;
int m_Score;
int m_X;
int m_Y;
Rectangle *m_Hitbox;
public:
Entity();
virtual ~Entity() {destroy_bitmap(m_Sprite);}
BITMAP *GetSprite() {return m_Sprite;}
int GetScore() {return m_Score;}
int GetX() {return m_X;}
int GetY() {return m_Y;}
Rectangle GetHitbox() {return *m_Hitbox;}
void SetSprite(EntityType type);
void SetScore(int value) {m_Score = value;}
void SetX(int value) {m_X = value;}
void SetY(int value) {m_Y = value;}
void SetHitbox(EntityType type);
};
Entity.cpp:
#include "Entity.h"
void Entity::SetSprite(EntityType type)
{
if (type == FACE)
m_Sprite = load_bitmap("face.bmp", NULL);
else if (type == POOP)
m_Sprite = load_bitmap("poop.bmp", NULL);
}
void Entity::SetHitbox(EntityType type)
{
if (type == FACE)
{
GetHitbox().x = m_X;
GetHitbox().y = m_Y;
GetHitbox().w = m_X + 32;
GetHitbox().h = m_Y + 32;
}
else if (type == POOP)
{
GetHitbox().x = m_X;
GetHitbox().y = m_Y;
GetHitbox().w = m_X + 16;
GetHitbox().h = m_Y + 16;
}
}
I'm working on compiling the code for Acellerated c++ chapter 15. I more or less copied the code straight out of the book, except in some places they defined things like constructors in the class body in the header file, and I separated them out to avoid link errors.
Below is the code; I attempted to compile it in Visual Studio 2010, but unfortunately it fails. It tells me it cannot create instances of the "String_Pic" and the other derived classes (Frame_Pic, HCat_Pic, and VCat_Pic) because it says they are still abstract classes. It says the culprit is the "display" function, which it says is undefined. However, I clearly define it for each derived class, as you can see below.
What's going on here?
Header:
#ifndef _GUARD_PIC_BASE_H
#define _GUARD_PIC_BASE_H
#include "Ptr.h"
#include <iostream>
#include <string>
#include <vector>
class Picture;
class Pic_base {
friend std::ostream& operator<<(std::ostream&, const Picture&);
friend class Frame_Pic;
friend class HCat_Pic;
friend class VCat_Pic;
friend class String_Pic;
typedef std::vector<std::string>::size_type ht_sz;
typedef std::string::size_type wd_sz;
virtual wd_sz width() const = 0;
virtual ht_sz height() const = 0;
virtual void display(std::ostream, ht_sz, bool) const = 0;
public:
virtual ~Pic_base(){ }
protected:
static void pad(std::ostream&, wd_sz, wd_sz);
};
// public interface class and operations
class Picture {
friend std::ostream& operator<<(std::ostream&, const Picture&);
friend Picture frame(const Picture&);
friend Picture hcat(const Picture&, const Picture&);
friend Picture vcat(const Picture&, const Picture&);
public:
Picture(const std::vector<std::string>& =
std::vector<std::string>());
private:
Picture(Pic_base* ptr); //here's one difference
Ptr<Pic_base> p;
};
Picture frame(const Picture&);
Picture hcat(const Picture&, const Picture&);
Picture vcat(const Picture&, const Picture&);
std::ostream& operator<<(std::ostream&, const Picture&);
class String_Pic: public Pic_base {
friend class Picture;
std::vector<std::string> data;
String_Pic(const std::vector<std::string>&);
wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};
class VCat_Pic: public Pic_base {
friend Picture vcat(const Picture&, const Picture&);
Ptr<Pic_base> top, bottom;
VCat_Pic(const Ptr<Pic_base>&, const Ptr<Pic_base>&);
wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};
class HCat_Pic: public Pic_base {
friend Picture hcat(const Picture&, const Picture&);
Ptr<Pic_base> left, right;
HCat_Pic(const Ptr<Pic_base>&, const Ptr<Pic_base>&);
wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};
class Frame_Pic: public Pic_base {
friend Picture frame(const Picture&);
Ptr<Pic_base> p;
Frame_Pic(const Ptr<Pic_base>& pic);
wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};
#endif
.cpp/implementation file:
#include "Ptr.h"
#include "Pic_Base.h"
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
//Picture-Specific Functions:
Picture::Picture(Pic_base* ptr):p(ptr) {}
Picture::Picture(const vector<string>& v): p(new String_Pic(v)) { }
//Frame-Specific Functions:
Frame_Pic::Frame_Pic(const Ptr<Pic_base>& pic): p(pic) {}
Pic_base::wd_sz Frame_Pic::width() const { return p->width() + 4; }
Pic_base::ht_sz Frame_Pic::height() const { return p->height() + 4; }
void Frame_Pic::display(ostream& os, ht_sz row, bool do_pad) const{
if (row >= height()) {
// out of range
if (do_pad)
pad(os, 0, width());
} else {
if (row == 0 || row == height() - 1) {
// top or bottom row
os << string(width(), '*');
} else if (row == 1 || row == height() - 2) {
// second from fop or bottom row
os << "*";
pad(os, 1, width() - 1);
os << "*";
} else {
// interior row
os << "* ";
p->display(os, row - 2, true);
os << " *";
}
}
}
Picture frame(const Picture& pic){
return new Frame_Pic(pic.p);
}
//HCat-Specific Functions:
HCat_Pic::HCat_Pic(const Ptr<Pic_base>& l, const Ptr<Pic_base>& r): left(l), right(r) { }
HCat_Pic::HCat_Pic(const Ptr<Pic_base>& l, const Ptr<Pic_base>&r):
left(l), right(r) { }
Pic_base::wd_sz width() const { return left->width() + right->width(); }
Pic_base::ht_sz height() const { return max(left->height(), right->heigth()); }
void HCat_Pic::display(ostream& os, ht_sz row, bool do_pad) const{
left->display(os, row, do_pad || row < right->height());
right->display(os, row, do_pad);
}
Picture hcat(const Picture& l, const Picture& r){
return new HCat_Pic(l.p, r.p);
}
//VCat-Specific Functions:
VCat_Pic::VCat_Pic(const Ptr<Pic_base>& t, const Ptr<Pic_base>& b): top(t), bottom(b) { }
Picture vcat(const Picture& t, const Picture& b){
return new VCat_Pic(t.p, b.p);
}
Pic_base::wd_sz VCat_Pic::width() const {
return max(top->width(), bottom->width());
}
Pic_base::ht_sz VCat_Pic::height() const{
return top->height() + bottom->height();
}
void VCat_Pic::display(ostream& os, ht_sz row, bool do_pad) const{
wd_sz w = 0;
if (row < top->height()) {
// we are in the top subpicture
top->display(os, row, do_pad);
w = top->width();
} else if (row < height()) {
// we are in the bottom subpicture
bottom->display(os, row - top->height(), do_pad);
w = bottom->width();
}
if (do_pad)
pad(os, w, width());
}
//String_Pic-Specific Functions:
String_Pic::String_Pic(const std::vector<std::string>& v): data(v) { }
Pic_base::ht_sz String_Pic::height() const { return data.size(); }
Pic_base::wd_sz String_Pic::width() const{
Pic_base::wd_sz n = 0;
for (Pic_base::ht_sz i = 0; i != data.size(); ++i)
n = max(n, data[i].size());
return n;
}
void String_Pic::display(ostream& os, ht_sz row, bool do_pad) const{
wd_sz start = 0;
// write the row if we're still in range
if (row < height()) {
os << data[row];
start = data[row].size();
}
// pad the output if necessary
if (do_pad)
pad(os, start, width());
}
//Pic_base-Specific functions:
void Pic_base::pad(std::ostream& os, wd_sz beg, wd_sz end) {
while (beg != end) {
os << " ";
++beg;
}
}
//Non-Specific Functions:
ostream& operator<<(ostream& os, const Picture& picture){
const Pic_base::ht_sz ht = picture.p->height();
for (Pic_base::ht_sz i = 0; i != ht; ++i) {
picture.p->display(os, i, false);
os << endl;
}
return os;
}
You declare the pure virtual function as taking a ofstream object by value, while all your subclasses define it as taking a reference to one.
virtual void display(std::ostream, ht_sz, bool) const = 0;
vs
void display(std::ostream&, ht_sz, bool) const;
^
Pi_base declares display with this signature:
virtual void display(std::ostream, ht_sz, bool) const = 0;
But your derived classes declare it with this signature:
void display(std::ostream&, ht_sz, bool) const;
Compare them closely and you'll see that your base class takes a std::ostream while your derived classes take a std::ostream&.