I have the following code:
class ISubscriber;
class News {
public:
float getVersion() { return this->version; }
void setVersion(float state) { this->version= state; this->notifyAllSubscribers(); }
void attach(ISubscriber *observer) { this->subscribers.push_back(observer); }
void notifyAllSubscribers() {
for (vector<ISubscriber*>::iterator it = subscribers.begin(); it != subscribers.end(); it++){
(*(*it)).update();
}
}
private:
vector<ISubscriber*> subscribers;
float version;
};
class ISubscriber {
public:
News *news;
virtual void update() = 0;
};
class Subscriber1 : public ISubscriber {
public:
Subscriber1(News *news) { this->news = news; this->news->attach(this); }
void update() override { cout << "Subscriber1: A new version of the newspaper has been launched (v" << this->news->getVersion() << ")" << endl; }
};
class Subscriber2 : public ISubscriber {
public:
Subscriber2(News *news) { this->news = news; this->news->attach(this); }
void update() override { cout << "Subscriber2: A new version of the newspaper has been launched (v" << this->news->getVersion() << ")" << endl; }
};
int main(int argc, char *argv[]) {
News newspaper;
newspaper.setVersion(2.1f);
Subscriber1 sb1(&newspaper);
Subscriber2 sb2(&newspaper);
return 0;
}
But strange errors happened:
The first error points to this code (*(*it)).update(); in news class.
Why that errors happened, what's the reason?
(*(*it)).update(); requires the type ISubscriber to be complete, just the forward declaration is not enough.
You could move the defnition of ISubscriber before the one of News, and give a forward declaration of News before that.
class News;
class ISubscriber {
public:
News *news;
virtual void update() = 0;
};
class News {
public:
float getVersion() { return this->version; }
void setVersion(float state) { this->version= state; this->notifyAllSubscribers(); }
void attach(ISubscriber *observer) { this->subscribers.push_back(observer); }
void notifyAllSubscribers() {
for (vector<ISubscriber*>::iterator it = subscribers.begin(); it != subscribers.end(); it++){
(*(*it)).update();
}
}
private:
vector<ISubscriber*> subscribers;
float version;
};
Related
I have 1 base class, Item, and 3 derived classes: CD, Book, & List.
I figured out how to print out and add Item objects, regardless of whether it's a Book or CD, in a vector within a List object. But I can't figure out how to print only Books or only CDs. I can't make any mentions of a CD or Book class in the List class, and I can't move the bool isBook or isCD members to the base class.
class Item
{
protected:
string name;
int id;
public:
//pure virtual methods (ex: virtual bool isID(int);
};
class CD: public Item
{
private:
bool isCD;
public:
//defining virtual methods from base class for class specific operations
virtual string format() { return "Artist: " + name }
};
class Book: public Item
{
private:
bool isBook;
public:
//defining virtual methods from base class for class specific operations
virtual string format() { return "Author: " + name }
};
class List: public Item
{
private:
vector<Item*> holdings;
public:
void Add(Item &adding) {} // already figured out
void printAll() // print all objects in vector regardless of type Book or CD
{
for(auto &i: holdings)
cout << i->format() << '\n';
}
void printBooks(){}
void PrintCDs(){}
}
You don't need the isCD and isBook boolean members in each class. You can use dynamic_cast instead, eg:
class List: public Item
{
private:
vector<Item*> holdings;
public:
...
void printAll() const
{
for(auto *i: holdings)
cout << i->format() << '\n';
}
void printBooks() const
{
for(auto *i: holdings)
{
if (Book *b = dynamic_cast<Book*>(i))
cout << b->format() << '\n';
}
}
void PrintCDs() const
{
for(auto *i: holdings)
{
if (CD *c = dynamic_cast<CD*>(i))
cout << c->format() << '\n';
}
}
};
If you don't want to use this approach, then you can use some additional virtual methods instead, eg:
class Item
{
...
public:
...
virtual bool isBook() const { return false; }
virtual bool isCD() const { return false; }
};
class CD: public Item
{
...
public:
...
bool isCD() const override { return true; }
};
class Book: public Item
{
...
public:
...
bool isBook() const override { return true; }
};
class List: public Item
{
private:
vector<Item*> holdings;
public:
...
void printAll() const
{
for(auto *i: holdings)
cout << i->format() << '\n';
}
void printBooks() const
{
for(auto *i: holdings)
{
if (i->isBook())
cout << i->format() << '\n';
}
}
void PrintCDs() const
{
for(auto *i: holdings)
{
if (i->isCD())
cout << i->format() << '\n';
}
}
};
Alternatively:
enum ItemType { itCD, itBook };
class Item
{
...
public:
...
virtual ItemType getType() const = 0;
};
class CD: public Item
{
...
public:
...
ItemType getType() const override { return itCD; }
};
class Book: public Item
{
...
public:
...
ItemType getType() const override { return itBook; }
};
class List: public Item
{
private:
vector<Item*> holdings;
public:
...
void printAll() const
{
for(auto *i: holdings)
cout << i->format() << '\n';
}
void printBooks() const
{
for(auto *i: holdings)
{
if (i->getType() == itBook)
cout << i->format() << '\n';
}
}
void PrintCDs() const
{
for(auto *i: holdings)
{
if (i->getType() == itCD)
cout << i->format() << '\n';
}
}
};
I have an abstract class "Mark" and it has a child class "Int_num". I also have a "Subject" class. I want a pointer to the address in the memory of the "Mark" class to be written to the "mark" parameter when calling its constructor. What should I do to make the mark pointer point to the "Mark" class?" occurred, after the compiler complaint about "expression must have class type" or something like that in mark.print_mark()?
class Mark {
private:
int mark;
public:
virtual void change_mark(int);
virtual void print_mark();
virtual int return_mark();
};
class Int_mark : public Mark {
private:
int mark;
public:
Int_mark();
Int_mark(int);
~Int_mark();
void change_mark(int = 0);
void print_mark() const;
int return_mark() const;
};
Int_mark::Int_mark() {
std::string str_mark;
std::cout << "New mark: ";
std::cin.ignore();
std::getline(std::cin, str_mark);
str_mark = ltrim(rtrim(str_mark));
int new_mark;
try {
new_mark = stoi(str_mark);
} catch(...) {
std::cout <<"wq";
mark = 1;
return ;
}
try {
if((new_mark < 1) || (new_mark > 5))
throw 1;
else
mark = new_mark;
} catch(int a) {
std::cout << "qw" << std::endl;
mark = 1;
}
}
void Int_mark::print_mark() const {
std::cout << "Mark: " << mark << std::endl;
}
Subject
#include "Mark.h"
#include <string>
#include <vector>
class Subject {
private:
std::string name_subject;
std::string type_subject;
unsigned hour_subject = 0;
void *mark = nullptr;
public:
Subject();
Subject(std::string, int);
Subject(std::string, bool);
~Subject();
void change_mark(unsigned);
void change_mark(bool);
void rename_subj(std::string);
void add_hour(unsigned);
};
Subject::Subject() {
std::string name_sub;
std::cout << "Введите название предмета: ";
getline(std::cin, name_sub);
name_sub = split_string(name_sub);
name_subject = name_sub;
int select = 2;
if(select == 1) {
type_subject = "Bool";
//mark = new Bool_mark();
} else {
type_subject = "Int";
mark = new Int_mark();
//What should I do to make the mark pointer point to the "Mark" class?
mark.print_mark();
}
}
main
#include "subject/Subject.h"
using namespace std;
int main() {
Subject q;
}
What am I doing wrong? How should I do this?
The pointer mark is of type void *. You could cast it with
static_cast<Int_mark*>(mark)
and call the function with
static_cast<Int_mark*>(mark)->print_mark();
But usually in OOP mark would be a pointer to the base class
Mark *mark = nullptr;
Now you can check for errors with
mark = new Int_mark();
auto *m = dynamic_cast<Int_mark*>(mark);
if (m)
m->print_mark();
Remember the virtual destructor in the base class
virtual ~Mark();
When to use virtual destructors?
Here is a fixed version of your code:
#include <iostream>
#include <string>
#include <vector>
class Mark {
public:
virtual ~Mark() = default;
//virtual void change_mark(int) = 0;
virtual void print_mark() const = 0;
//virtual int return_mark() const = 0;
};
class Int_mark : public Mark {
private:
int mark;
public:
Int_mark();
Int_mark(int);
~Int_mark() override = default;
//void change_mark(int = 0) override;
void print_mark() const override;
//int return_mark() const override;
};
Int_mark::Int_mark() {
std::string str_mark;
std::cout << "New mark: ";
std::cin.ignore();
std::getline(std::cin, str_mark);
//str_mark = ltrim(rtrim(str_mark));
int new_mark;
try {
new_mark = stoi(str_mark);
} catch(...) {
std::cout <<"wq";
mark = 1;
return ;
}
try {
if((new_mark < 1) || (new_mark > 5))
throw 1;
else
mark = new_mark;
} catch(int a) {
std::cout << "qw" << std::endl;
mark = 1;
}
}
void Int_mark::print_mark() const {
std::cout << "Mark: " << mark << std::endl;
}
class Subject {
private:
std::string name_subject;
std::string type_subject;
unsigned hour_subject = 0;
Mark *mark = nullptr;
public:
Subject();
Subject(std::string, int);
Subject(std::string, bool);
~Subject();
void change_mark(unsigned);
void change_mark(bool);
void rename_subj(std::string);
void add_hour(unsigned);
};
Subject::Subject() {
std::string name_sub;
std::cout << "Введите название предмета: ";
getline(std::cin, name_sub);
//name_sub = split_string(name_sub);
name_subject = name_sub;
int select = 2;
if(select == 1) {
type_subject = "Bool";
//mark = new Bool_mark();
} else {
type_subject = "Int";
mark = new Int_mark();
auto *m = dynamic_cast<Int_mark*>(mark);
if (m)
m->print_mark();
}
}
Subject::~Subject() {
delete mark;
}
int main() {
Subject q;
}
Since I did not correctly understand the question in the first place, here a way how you can call the member function of base class Mark by object of derived class Int_Mark:
Int_mark *mark = new Int_mark();
mark->print_mark(); // calls member of the class Int_mark
mark->Mark::print_mark(); // calls member of the class Mark
Make sure that Mark::print_mark() is also defined and not just Int_mark::print_mark()
I'm making a state machine for switching game states (playing->menu->setup) in my game engine, but I'm getting a segmentation fault. I can change the game state fine from upper level, but how can I change the game state from within a game state?
Here's a minimal code example:
#include <iostream>
#include <vector>
class GameStateManager;
class GameState {
public:
GameState(GameStateManager* StateManager) {
StateManager = stateManager;
};
virtual ~GameState();
virtual void update() = 0;
GameStateManager* stateManager;
};
class GameStateManager {
public:
GameStateManager();
~GameStateManager();
void changeGameState(GameState* state) {
if(!running) {
running = true;
}
// Cleanup the current state
if(!gameStates.empty()) {
for(unsigned int i = 0; i < gameStates.size(); i++) {
delete gameStates[i];
}
gameStates.clear();
std::cout << "Cleaning up GameState" << std::endl;
}
// Store and initialize the new game state
gameStates.push_back(state);
};
void update() {
if(!gameStates.empty()) {
gameStates.back()->update();
}
};
std::vector<GameState*> gameStates;
bool running;
};
class PlayState : public GameState {
public:
PlayState(GameStateManager* stateManager) : GameState(stateManager) {};
~PlayState();
void update() override {
// On some flag, initiate the next level
nextLevel();
};
void nextLevel() {
stateManager->changeGameState(new PlayState(stateManager));
};
};
int main() {
GameStateManager stateManager;
stateManager.changeGameState(new PlayState(&stateManager));
while(stateManager.running) {
for(unsigned int i = 0; i < 10000; i++) {
std::cout << "Round: " << i << std::endl;
// Segmentation fault here
stateManager.update();
// This works
//stateManager.changeGameState(new PlayState(&stateManager));
}
stateManager.running = false;
}
return 0;
}
for some reason the stateManager is not being set in the GameState constructor.
so try this:
class GameState {
public:
GameState(GameStateManager* StateManager) : stateManager(StateManager)
{
};
virtual ~GameState();
virtual void update() = 0;
GameStateManager* stateManager;
};
I have a problem with a c++ code I just written. The code is a sample of the Builder design pattern. I created an abstract builder class, and two classes inherited from this class: MonsterBuilder and RuffianBuilder. I created a Builder class, this class receives a Monster or a RuffianBuilder, and constructs a new instance of these classes. The problem comes here: if the MonsterBuilder class is used to build a new instance the program terminates with an error (a.exe has stopped working). If the Builder receives a RuffianBuilder, it constructs a new instance without an error. Here is the sample code:
#include <iostream>
class Character
{
private:
// Attributes
int dex;
int str;
int end;
// skills
int lockpick;
int guns;
int sneak;
/***************************************** Setters ********************************************************/
// Attribute setters
public:
void setStrength(const int &s)
{
this->str = s;
}
void setDexterity(const int &d)
{
this->dex = d;
}
void setEndurance(const int &e)
{
this->str = e;
}
// Skill setters
void setLockpick(const int &s)
{
this->lockpick = s;
}
void setSneak(const int &s)
{
this->sneak = s;
}
void setGuns(const int &s)
{
this->guns = s;
}
int getGuns()
{
return this->guns;
}
int getStrength()
{
return this->str;
}
};
/* Abstract builder */
class CharacterBuilder
{
protected:
Character * int_character;
public:
Character * getCharacter()
{
return int_character;
}
void buildCharacter()
{
int_character = new Character;
}
virtual void buildSkills() = 0;
virtual void buildAttributes() = 0;
};
class MonsterBuilder : public CharacterBuilder
{
public:
virtual void buildSkills()
{
int_character->setLockpick(10);
int_character->setSneak(12);
int_character->setGuns(50);
}
virtual void buildAttributes()
{
int_character->setStrength(5);
int_character->setDexterity(5);
int_character->setEndurance(5);
}
};
class RuffianBuilder : public CharacterBuilder
{
public:
virtual void buildSkills()
{
int_character->setLockpick(10);
int_character->setSneak(12);
int_character->setGuns(50);
}
virtual void buildAttributes()
{
int_character->setStrength(5);
int_character->setDexterity(5);
int_character->setEndurance(5);
}
};
class Builder
{
public:
void setBuilder(CharacterBuilder * builder)
{
this->builder = builder;
}
Character * getCharacter()
{
return builder->getCharacter();
}
void buildCharacter()
{
//std::cout << builder->buildSkills;
builder->buildSkills();
builder->buildAttributes();
}
private:
CharacterBuilder * builder;
};
int main()
{
Builder B;
RuffianBuilder R;
MonsterBuilder Mo;
B.setBuilder(&R);
B.buildCharacter();
std::cout << B.getCharacter()->getGuns();
std::cout << B.getCharacter()->getStrength();
B.setBuilder(&Mo);
B.buildCharacter();
//std::cout << B.getCharacter()->getStrength();
return 0;
}
What causes this problem? Could somebody explain it?
Reading uninitlalized variable will cause undefined behavior.
I added builder->buildCharacter(); to Builder::buildCharacter() and then this code seems working well.
class Builder
{
public:
void setBuilder(CharacterBuilder * builder)
{
this->builder = builder;
}
Character * getCharacter()
{
return builder->getCharacter();
}
void buildCharacter()
{
//std::cout << builder->buildSkills;
builder->buildCharacter(); // add this line
builder->buildSkills();
builder->buildAttributes();
}
private:
CharacterBuilder * builder;
};
#include<iostream.h>
#include<conio.h>
using namespace std;
class SpaceShip {};
class GiantSpaceShip : public SpaceShip {};
class Asteroid {
public:
virtual void CollideWith(SpaceShip *) {
cout << "Asteroid hit a SpaceShip" << endl;
}
virtual void CollideWith(GiantSpaceShip *) {
cout << "Asteroid hit a GiantSpaceShip" << endl;
}
};
class ExplodingAsteroid : public Asteroid {
public:
virtual void CollideWith(SpaceShip *) {
cout << "ExplodingAsteroid hit a SpaceShip" << endl;
}
virtual void CollideWith(GiantSpaceShip *) {
cout << "ExplodingAsteroid hit a GiantSpaceShip" << endl;
}
};
int main()
{
SpaceShip * s = new GiantSpaceShip();
Asteroid * a = new ExplodingAsteroid();
a->CollideWith(s);
getch();
return 0;
}
How can I enable double dispatch in C++?
This is not single dispatch but double dispatch: you want the method to depend both on the actual/real type of the object it is invoked on, and on the actual/real type of the argument.
This issue can be solved by the Visitor design pattern.
Luc is right on with using the Visitor pattern, I'm just expanding on that by giving an example of how you could do it.
#include <iostream>
#include <conio.h>
using namespace std;
class SpaceObject;
class SpaceShip;
class GiantSpaceShip;
class Asteroid;
class ExplodingAsteroid;
class SpaceObject {
public:
virtual void CollideWith(SpaceObject*) {}
virtual void CollideWith(SpaceShip*) {}
virtual void CollideWith(GiantSpaceShip*) {}
virtual void CollideWith(Asteroid*) {}
virtual void CollideWith(ExplodingAsteroid*) {}
};
class Asteroid : public SpaceObject {
public:
virtual void CollideWith(SpaceObject* o) { o->CollideWith(this); }
virtual void CollideWith(SpaceShip *) { cout << "Asteroid hit a SpaceShip" << endl; }
virtual void CollideWith(GiantSpaceShip *) { cout << "Asteroid hit a GiantSpaceShip" << endl; }
};
class ExplodingAsteroid : public Asteroid {
public:
virtual void CollideWith(SpaceObject* o) { o->CollideWith(this); }
virtual void CollideWith(SpaceShip *) { cout << "ExplodingAsteroid hit a SpaceShip" << endl; }
virtual void CollideWith(GiantSpaceShip *) { cout << "ExplodingAsteroid hit a GiantSpaceShip" << endl; }
};
class SpaceShip : public SpaceObject {
public:
virtual void CollideWith(SpaceObject* o) { o->CollideWith(this); }
virtual void CollideWith(Asteroid* o) { o->Asteroid::CollideWith(this); }
virtual void CollideWith(ExplodingAsteroid* o) { o->ExplodingAsteroid::CollideWith(this); }
};
class GiantSpaceShip : public SpaceShip {
public:
virtual void CollideWith(SpaceObject* o) { o->CollideWith(this); }
virtual void CollideWith(Asteroid* o) { o->Asteroid::CollideWith(this); }
virtual void CollideWith(ExplodingAsteroid* o) { o->ExplodingAsteroid::CollideWith(this); }
};
int main()
{
SpaceObject* s = new GiantSpaceShip();
SpaceObject* a = new ExplodingAsteroid();
a->CollideWith(s);
getch();
return 0;
}