GoogleTest Mocking object method call fail - c++

Hi so this is my first time utilizing googleTest Mocking. The general setup of the project is that coffeeMachine has an object coffeeStorage and coffeeStockService that it calls methods from coffeeMachine methods. I'm trying to create a mock test for the objects coffeeStorage and coffeeStockService but it's not recognizing the Expected Calls when I assign the mock objects to the coffeeMachine instance.
Trying to implement GoogleTest's mocking test framework but it's not recognizing the EXPECTED_CALL and also not letting me use mockedCoffeeStorage as a parameter to the method calls for mockedCoffeeStockService.. StockService Expected Call is because CoffeeMachine is also calling that but I passed in the coffeeStorage as a parameter. Is that possible for a mock object to cause a method that is using another mock object as the parameter and still expect the method to be called? Should I refactor and not include all the object references to the methods for CoffeeMachine since I already declare a CofeeStorage and CoffeeStockService object? Thank you so much
class coffeeMachine {
public:
coffeeStorage* CoffeeStorage;
coffeeStockService* CoffeeStockService;
bool coffeeServed = false;
coffeeMachine(coffeeStorage* CoffeeStorage, coffeeStockService* CoffeeStockService);
void start(string langIn);
void stop();
void descale();
void showSettings();
void hideSettings();
map<string, string> getSetting();
string message(coffeeStorage& CoffeeStorage);
void takeCoffee(coffeeStorage& CoffeeStorage);
void fillTank(coffeeStorage& CoffeeStorage, coffeeStockService& CoffeeStockService);
void fillBeans(coffeeStorage& CoffeeStorage, coffeeStockService& CoffeeStockService);
void emptyGrounds(coffeeStorage& CoffeeStorage, coffeeStockService& CoffeeStockService);
bool isDescalingNeeded();
class coffeeStorage {
private:
int waterStorage;
int beanStorage;
int trashStorage;
public:
//virtual ~coffeeStorage(){}
coffeeStorage();
virtual void takeCoffeeStorage();
virtual void setWaterStorage(int amount);
virtual void setBeansStorage(int amount);
virtual void emptyTrashStorage();
virtual int checkWater();
virtual int checkBeans();
virtual int checkTrashStorage();
};
class mockCoffeeStorage : public coffeeStorage {
private:
int waterStorage;
int beanStorage;
int trashStorage;
public:
MOCK_METHOD(void, takeCoffeeStorage, (), (override));
MOCK_METHOD(void, setWaterStorage, (int amount), (override));
MOCK_METHOD(void, setBeansStorage, (int amount), (override));
MOCK_METHOD(void, emptyTrashStorage, (), (override));
MOCK_METHOD(int, checkWater, (), (override));
MOCK_METHOD(int, checkBeans, (), (override));
MOCK_METHOD(int, checkTrashStorage, (), (override));
};
coffeeMachine::coffeeMachine(coffeeStorage* CoffeeStorage_, coffeeStockService* CoffeeStockService_){
waterHardness = "2";
grinder = "medium";
started = false;
coffeeServed = false;
settingsDisplayed = false;
CoffeeStorage = CoffeeStorage_;
CoffeeStockService = CoffeeStockService_;
message(*CoffeeStorage_);
descale();
fillTank(*CoffeeStorage_, *CoffeeStockService_);
fillBeans(*CoffeeStorage_, *CoffeeStockService_);
emptyGrounds(*CoffeeStorage_, *CoffeeStockService_);
}
string coffeeMachine::message(coffeeStorage& CoffeeStorage){
if(!started) return "";
if (settingsDisplayed) return i18n("settings");
if (CoffeeStorage.checkWater() <= 10) return i18n("tank");
if (CoffeeStorage.checkBeans() < 3) return i18n("beans");
if (CoffeeStorage.checkTrashStorage() >= 30) return i18n("grounds");
if (isDescalingNeeded()) return i18n("descale");
return i18n("ready");
}
void coffeeMachine::takeCoffee(coffeeStorage& CoffeeStorage){
if (CoffeeStorage.checkWater() == 0 || CoffeeStorage.checkBeans() == 0) {
coffeeServed = false;
} else {
coffeeServed = true;
CoffeeStorage.takeCoffeeStorage();
countdownToDescale -= 1;
}
}
void coffeeMachine::fillTank(coffeeStorage& CoffeeStorage, coffeeStockService& CoffeeStockService){
CoffeeStockService.restockWater(CoffeeStorage);
}
void coffeeMachine::fillBeans(coffeeStorage& CoffeeStorage, coffeeStockService& CoffeeStockService){
CoffeeStockService.restockBeans(CoffeeStorage);
}
void coffeeMachine::emptyGrounds(coffeeStorage& CoffeeStorage, coffeeStockService& CoffeeStockService){
CoffeeStockService.emptyTrash(CoffeeStorage);
}
TEST(MockObjTest, TestObjectCallsWithMock) {
mockCoffeeStorage mockedCoffeeStorage;
mockCoffeeStockService mockedCoffeeStockService;
EXPECT_CALL(mockedCoffeeStorage, checkWater())
.Times(AtLeast(1));
EXPECT_CALL(mockedCoffeeStorage, checkBeans())
.Times(AtLeast(1));
EXPECT_CALL(mockedCoffeeStorage, takeCoffeeStorage())
.Times(AtLeast(1));
coffeeMachine coffeeTest = coffeeMachine(&mockedCoffeeStorage, &mockedCoffeeStockService);
std::cout<< "Address of mockedCoffeeStorage: " << &mockedCoffeeStorage << "\n";
std::cout<< "Address of mockedCoffeeStockService: " << &mockedCoffeeStockService << "\n";
// EXPECT_CALL(mockedCoffeeStockService, restockWater(mockedCoffeeStorage))
// .Times(AtLeast(1));
// EXPECT_CALL(mockedCoffeeStockService, restockBeans(mockedCoffeeStorage))
// .Times(AtLeast(1));
// EXPECT_CALL(mockedCoffeeStockService, emptyTrash(mockedCoffeeStorage))
// .Times(AtLeast(1));
coffeeTest.start("en");
for(int i = 0; i < 10; i++)
{
if(coffeeTest.getBeansContent(mockedCoffeeStorage) < 5)
coffeeTest.fillBeans(mockedCoffeeStorage, mockedCoffeeStockService);
if(coffeeTest.getGroundsContent(mockedCoffeeStorage) > 20)
coffeeTest.emptyGrounds(mockedCoffeeStorage, mockedCoffeeStockService);
if(coffeeTest.getTankContent(mockedCoffeeStorage) < 15)
coffeeTest.fillTank(mockedCoffeeStorage, mockedCoffeeStockService);
coffeeTest.takeCoffee(mockedCoffeeStorage);
}
}

It's perfectly fine to set expect calls one mock with other mock as a parameter.
no need to pass the objects to each method - you can access them inside your functions because they're are members. This technique is called 'dependency injection'.
See this code (using GMock 1.8, so mock definition is slightly different):
// pure virt. interface, remember about virtual dtor
class coffeeStorage {
public:
virtual ~coffeeStorage() = default;
virtual void takeCoffeeStorage() = 0;
virtual void setWaterStorage(int amount) = 0;
virtual void setBeansStorage(int amount) = 0;
virtual void emptyTrashStorage() = 0;
virtual int checkWater() = 0;
virtual int checkBeans() = 0;
virtual int checkTrashStorage() = 0;
};
class coffeeStockService {
public:
virtual ~coffeeStockService() = default;
virtual void restockWater(coffeeStorage& storeage) = 0;
};
class coffeeMachine {
public:
coffeeMachine(coffeeStorage* CoffeeStorage, coffeeStockService* CoffeeStockService);
void fillTank() {
CoffeeStockService->restockWater(*CoffeeStorage);
}
void takeCoffee() {
if (CoffeeStorage->checkWater() == 0 || CoffeeStorage->checkBeans() == 0) {
coffeeServed = false;
}
else {
coffeeServed = true;
CoffeeStorage->takeCoffeeStorage();
}
}
bool isCoffeeServed() {
return coffeeServed;
}
private:
coffeeStorage* CoffeeStorage;
coffeeStockService* CoffeeStockService;
bool coffeeServed{false};
};
coffeeMachine::coffeeMachine(coffeeStorage* CoffeeStorage_, coffeeStockService* CoffeeStockService_)
: CoffeeStorage{CoffeeStorage_}
, CoffeeStockService{CoffeeStockService_} {}
class mockCoffeeStorage : public coffeeStorage {
public:
MOCK_METHOD0(takeCoffeeStorage, void());
MOCK_METHOD1(setWaterStorage, void(int amount));
MOCK_METHOD1(setBeansStorage, void(int amount));
MOCK_METHOD0(emptyTrashStorage, void());
MOCK_METHOD0(checkWater, int());
MOCK_METHOD0(checkBeans, int());
MOCK_METHOD0(checkTrashStorage, int());
};
class mockCoffeeStockService : public coffeeStockService {
public:
MOCK_METHOD1(restockWater, void(coffeeStorage& storeage));
};
struct MockObjTest : public testing::Test {
mockCoffeeStorage mockedCoffeeStorage;
mockCoffeeStockService mockedCoffeeStockService;
coffeeMachine coffeeTest = coffeeMachine(&mockedCoffeeStorage, &mockedCoffeeStockService);
};
TEST_F(MockObjTest, When_FillingTank_Then_RestocksWater) {
// assert
EXPECT_CALL(mockedCoffeeStockService, restockWater(testing::Ref(mockedCoffeeStorage)));
// act
coffeeTest.fillTank();
}
TEST_F(MockObjTest, Given_NoWater_When_TakingCoffee_Then_CoffeeNotServed) {
// arrange
EXPECT_CALL(mockedCoffeeStorage, checkWater()).WillOnce(testing::Return(0));
// act
coffeeTest.takeCoffee();
// assert
ASSERT_FALSE(coffeeTest.isCoffeeServed());
}
TEST_F(MockObjTest, Given_EnoughWaterWaterAndBeans_When_TakingCoffee_Then_takeCoffeeStorageAndCoffeeServed) {
// arrange
EXPECT_CALL(mockedCoffeeStorage, checkWater()).WillOnce(testing::Return(1));
EXPECT_CALL(mockedCoffeeStorage, checkBeans()).WillOnce(testing::Return(1));
EXPECT_CALL(mockedCoffeeStorage, takeCoffeeStorage()); // this is more of the 'assert' part, but it cannot be moved to the end of the test
// act
coffeeTest.takeCoffee();
// assert
ASSERT_TRUE(coffeeTest.isCoffeeServed());
}
This is trimmed and simplified version of your code, but this should get you running. Always try to start with some v. easy, minimal test and build from this adding more complexity. If the tests becomes too complex/complicated, it is probably time to separate some parts of your code to the new class and test this class in separation.

Related

How can I use a QMap to store and look at my data?

I am new to QT started to try out some things with QMap as it seems like a useful tool. I already read some other forum threads but I wasnt able to answer my question. The user is supposed to add and edit different shapes via the GUI. For the shapes I first wrote an abstract base class:
#ifndef BASE_H
#define BASE_H
#include <QListWidget>
#include <QMap>
class Base
{
protected:
QVariantMap m_properties;
QString m_key;
void setKey(const QString& key){
this->m_key=key;
}
public:
Base(){}
virtual ~Base(){}
QString key(){
return m_key;
}
void setProperty(QString key, QVariant variant){
m_properties[key]=variant;
}
virtual void toRTC()=0;
};
#endif // BASE_H
one example of a subclass is an ellipse with the following cpp file:
#include "ellipse.h"
Ellipse::Ellipse(int Start_x, int Start_y, int Rad_x, int Rad_y): rad_x(Rad_x), rad_y(Rad_y), start_x(Start_x), start_y(Start_y)
{
this->setKey("ellipse");
this->setProperty("radX", rad_x);
this->setProperty("radY", rad_y);
this->setProperty("startX", start_x);
this->setProperty("startY", start_y);
}
void Ellipse::set_rad_x(int rad_x)
{
Base::setProperty("radX", rad_x);
}
void Ellipse::set_rad_y(int rad_y)
{
Base::setProperty("radY", rad_y);
}
void Ellipse::set_start_x(int start_x)
{
Base::setProperty("startX", start_x);
}
void Ellipse::set_start_y(int start_y)
{
Base::setProperty("startY", start_y);
}
int Ellipse::get_rad_x()
{
return m_properties["radX"].toInt();
}
int Ellipse::get_rad_y()
{
return m_properties["radY"].toInt();
}
int Ellipse::get_start_x()
{
return m_properties["startX"].toInt();
}
int Ellipse::get_start_y()
{
return m_properties["startY"].toInt();
}
First off, is this a correct approach for the cpp file? I feel my approach is vary laborious.
In my main window file I thought about storing my data in a simple Vector QVector<Base *> data_storage;
Ellipse *e_values = new Ellipse(ui->Ellipse_Value_start_x->value(),ui->Ellipse_Value_start_y->value(), ui->Ellipse_Value_rad_x->value(),ui->Ellipse_Value_rad_y->value());
data_storage.append(e_values);
To load the data, I thought it would be a good idea to use the key to check which object of data_storage I want to load, but I don't really know how I can access the data which is connected to my key.
if(data_storage[t]->key()=="ellipse"){
ui->Ellipse_Value_rad_x->setValue(data_storage[t]->) //how can I access the correct data?
}
I feel like I messed up the entire approach, like how to properly use keys, so how would I do that?
You need to declare all the behaviours you need in the base class. I don't see the need to have Base hold the data.
E.g. if you need to be able to read and write the UI, there should be methods to do that.
class Base
{
public:
virtual ~Base() = default;
virtual void toRTC() = 0;
virtual QVariantMap properties() const = 0;
virtual void writeUI(form_t * ui) const = 0;
virtual void readUI(const form_t * ui) = 0;
};
class Ellipse : public Base
{
int start_x;
int start_y;
int rad_x;
int rad_y;
public:
void toRTC() final { /* ??? */ }
QVariantMap properties() const final {
return { { "radX", rad_x }, { "radY", rad_y },
{ "startX", start_x }, { "startY", start_y } };
}
void writeUI(form_t * ui) const final {
ui->Ellipse_Value_rad_x->setValue(rad_x);
ui->Ellipse_Value_rad_y->setValue(rad_y);
ui->Ellipse_Value_start_x->setValue(start_x);
ui->Ellipse_Value_start_y->setValue(start_y);
}
void readUI(const form_t * ui) final {
rad_x = ui->Ellipse_Value_rad_x->value().toInt();
rad_y = ui->Ellipse_Value_rad_y->value().toInt();
start_x = ui->Ellipse_Value_start_x->value().toInt();
start_y = ui->Ellipse_Value_start_y->value().toInt();
}
};
If you don't want to tie your shapes to the UI, you could define a visitor interface, with a visit method for each shape type.
class ShapeVisitor
{
virtual void accept(Ellipse * ellipse) = 0;
/* virtual void accept(Rectangle * rectangle) = 0; // etc.. */
};
class Base
{
public:
virtual ~Base() = default;
virtual void toRTC() = 0;
virtual QVariantMap properties() const = 0;
virtual void visit(ShapeVisitor & visitor) = 0;
};
class Ellipse : public Base
{
public:
int start_x;
int start_y;
int rad_x;
int rad_y;
void toRTC() final { /* ??? */ }
QVariantMap properties() const final {
return { { "radX", rad_x }, { "radY", rad_y },
{ "startX", start_x }, { "startY", start_y } };
}
void visit(ShapeVisitor & visitor) final {
visitor.accept(this); // calls visitor::accept(Ellipse *)
}
};
class UIReadVisitor : public ShapeVisitor
{
form_t * ui
void accept(Ellipse * ellipse) final {
ellipse->rad_x = ui->Ellipse_Value_rad_x->value().toInt();
ellipse->rad_y = ui->Ellipse_Value_rad_y->value().toInt();
ellipse->start_x = ui->Ellipse_Value_start_x->value().toInt();
ellipse->start_y = ui->Ellipse_Value_start_y->value().toInt();
}
}
class UIWriteVisitor : public ShapeVisitor
{
form_t * ui;
void accept(Ellipse * ellipse) final {
ui->Ellipse_Value_rad_x->setValue(ellipse->rad_x);
ui->Ellipse_Value_rad_y->setValue(ellipse->rad_y);
ui->Ellipse_Value_start_x->setValue(ellipse->start_x);
ui->Ellipse_Value_start_y->setValue(ellipse->start_y);
}
}

How do I override a public member function of a juce voice?

Hi I am coding a synth in the Juce framework.
When my adsr is running I need to override isVoiceActive() and set it to true from inside the voice. This is a public member function of the SynthesiserVoice class.
virtual bool SynthesiserVoice::isVoiceActive ( ) const
Returns true if this voice is currently busy playing a sound.
By default this just checks the getCurrentlyPlayingNote() value, but
can be overridden for more advanced checking.
So in the voice I have another member function virtual void renderNextBlock() and from inside it I want to override isVoiceActive
class SynthVoice : public SynthesiserVoice
{
public:
void renderNextBlock (AudioBuffer <float> &outputBuffer, int startSample, int numSamples) override
{
for (int sample = startSample; sample < (startSample + numSamples); ++sample)
{
float env_value = adsr.getNextSample();
if(env_value > 0)
isVoiceActive = true; //???????
...
you cannot do this because isVoiceActive is not an attribute it's a function, you can use your isVoiceActive as a data member and not as a function member so you can assign it true or false. or if you want to work with function then you have to add '&' so you can assign to that function a value (if you don't use '&' then you cannot do what you want to do.
you have 2 choices:
1/ to use isVoiceActivat as a data member and you can do like this:
class SynthesiserVoice
{
public:
bool isVoiceActive;
};
class SynthVoice :public SynthesiserVoice
{
public:
oid renderNextBlock (AudioBuffer <float> &outputBuffer, int startSample, int numSamples) override
{
for (int sample = startSample; sample < (startSample + numSamples); ++sample)
{
float env_value = adsr.getNextSample();
if(env_value > 0)
isVoiceActive = true;
}
}
};
2/ to do the following:
class SynthesiserVoice
{
public:
bool i = false;
virtual bool& isVoiceActive() { return i; } // or virtual bool& isVoiceActive()=0;
};
class SynthVoice :public SynthesiserVoice
{
public:
bool& isVoiceActive()override { return i; }
void renderNextBlock (AudioBuffer <float> &outputBuffer, int startSample, int numSamples) override
{
for (int sample = startSample; sample < (startSample + numSamples); ++sample)
{
float env_value = adsr.getNextSample();
if(env_value > 0)
isVoiceActive ()= true;
}
}
};
Now you have to implement this to suit your functions and data.
Hope it's clear and helpful

When apply observer pattern an error occured

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;
};

Builder design pattern does not work for me

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;
};

Inheritance container of Parent type cannot hold children?

I have a parent Menu class and children MainMenu, SettingsMenu, PauseMenu, etc.
I want to be able to hold them all in a vector...
I can do
std::vector<Menu*> myVector;
and then typecast each one when I push_back in the vector
pMainMenu = new MainMenu;
myVector.push_back((Menu*)pMainMenu);
and it compiles but something's not working right down the road...
It doesn't have to be a vector but I want to be able to iterate through them.
I'm always trying to implement the Observer pattern and I'm having difficulties with inheritance as well in that area!
For the Observer pattern I have an Observer class and Game inherits Observer. I have a Subject class inherited by InputComponent. Subject has a vector of Observer* called vObserver and a function called addObserver(Observer* observer) and adds the passed pointer in vObserver. I also have a function called Notify(event e), which iterates through vObserver and calls their onNotify functions.
So in Game, I have an InputComponent instance called inputComp. I do inputComp.addObserver(this) and inputComp.vObserver.size() is 1. Good. I have a call to Notify in InputComponent which does get triggered, but when it executes, the vObserver.size inside Subject is 0... idk what I'm doing wrong
EDIT:
class Menu
{
public:
virtual void draw() = 0;
virtual void onMouseMove(int x, int y) = 0;
virtual void onMouseButton(int button, bool is_down) = 0;
friend class InputComponent;
friend class MainMenuInputComponent;
protected:
SDL_Renderer* _renderer;
std::vector<Button> vButton;
std::vector<SDL_Texture *> vTexture;
};
class MainMenu : public Menu
{
public:
MainMenu(SDL_Renderer* renderer);
virtual void draw();
virtual void onMouseMove(int x, int y);
virtual void onMouseButton(int button, bool is_down);
friend class MainMenuInputComponent;
};
class InputComponent: public Subject
{
public:
virtual void processInput()
{}
static bool isMouseWithin(int mouseX, int mouseY, SDL_Rect rect)
{
if (mouseX >= rect.x && mouseX <= rect.x + rect.w && mouseY >= rect.y && mouseY <= rect.y + rect.h)
return true;
else
return false;
}
};
class MainMenuInputComponent : public InputComponent
{
public:
MainMenuInputComponent(MainMenu* owner)
:_owner(owner){}
virtual void processInput();
virtual void onBtnClick(std::string btnName);
MainMenu* _owner;
};
class Game : public Observer
{
public:
Game();
void initSDL();
void initGame();
void processGameInput();
void renderGame();
void update();
virtual void onNotify(Events e);
SDL_Window* myWindow;
SDL_Renderer* myRenderer;
std::vector<MainMenuInputComponent> vInputComponent;
std::stack<MainMenu*> menuStack;
};
Game::Game()
{
initSDL();
initGame();
}
void Game::initGame()
{
//Create the Main Menu
MainMenu* pMainMenu = new MainMenu(myRenderer);
//Add menu to the stack
menuStack.push((pMainMenu));
//Add it's components to respective arrays
MainMenuInputComponent inputComp = MainMenuInputComponent(pMainMenu);
vInputComponent.push_back(inputComp);
//Add Observer/Subject relationship.
inputComp.addObserver((Observer*)this);
int bob = (int)inputComp.vObserver.size(); //to see if size went up
}
void Game::processGameInput()
{
if (!menuStack.empty())
{
for (int i = 0; i < (int)vInputComponent.size(); i++)
{
//Menu* compOwner = (Menu*)(vInputComponent[i]._owner);
//std::unique_ptr<Menu, std::default_delete<Menu>> a = menuStack.top();
if ((vInputComponent[i]._owner) == menuStack.top())
{
vInputComponent[i].processInput();
}
//vInputComponent[i].processInput();
}
}
else
for (int i = 0; i < (int)vInputComponent.size(); i++)
{
vInputComponent[i].processInput();
}
}
void Game::renderGame()
{
SDL_RenderClear(myRenderer);
MainMenu* bob = menuStack.top();
if (!menuStack.empty())
(menuStack.top())->draw();
SDL_RenderPresent(myRenderer);
}
void Game::onNotify(Events event)
{
switch (event)
{
case POP_MENU:
menuStack.pop();
break;
case GOTO_SETTINGS:
//Menu* pSettingsMenu =(Menu*)(new SettingsMenu(myRenderer));
//menuStack.push(std::unique_ptr<Menu>(pSettingsMenu));
break;
// Handle other events, and update heroIsOnBridge_...
}
}
class Subject
{
public:
void addObserver(Observer* observer)
{
vObserver.push_back(observer);
}
void removeObserver(Observer* observer)
{
//vObserver.erase(std::find(vObserver.begin(), vObserver.end(), 8));
}
std::vector<Observer*> vObserver;
protected:
void notify(Events e)
{
for (int i = 0; i < (int)vObserver.size(); i++)
{
vObserver[i]->onNotify(e);
}
}
};
class Observer
{
public:
virtual ~Observer() {}
virtual void onNotify(Events e) = 0;
};
If MainMenu publically inherits from Menu, then you shouldn't even need to type cast the pointer to MainMenu to Menu at all. That is, this should work:
class Menu {};
class MainMenu : public Menu {};
std::vector<Menu*> myVector;
MainMenu* pMainMenu = // ...
myVector.push_back(pMainMenu);
However, what you really should be doing is using something like shared_ptr or unique_ptr. Here's a more complete example, using shared_ptr:
#include <vector>
#include <memory>
#include <iostream>
class Menu
{
public:
virtual void on_event() = 0;
// virtual destructor needed for polymorphic base classes
virtual ~Menu() {}
};
class MainMenu : public Menu
{
public:
virtual void on_event()
{
std::cout << "Hello world! from MainMenu" << std::endl;
}
};
class PauseMenu : public Menu
{
public:
virtual void on_event()
{
std::cout << "Hello world! from PauseMenu" << std::endl;
}
};
class SettingsMenu : public Menu
{
public:
virtual void on_event()
{
std::cout << "Hello world! from SettingsMenu" << std::endl;
}
};
int main()
{
std::vector<std::shared_ptr<Menu>> myVector;
myVector.push_back(std::make_shared<MainMenu>());
myVector.push_back(std::make_shared<PauseMenu>());
myVector.push_back(std::make_shared<SettingsMenu>());
for(auto& menu : myVector) {
menu->on_event();
}
return 0;
}
Expected output:
Hello world! from MainMenu
Hello world! from PauseMenu
Hello world! from SettingsMenu
This should also work and gives you the bonus feature of taking care of memory management for you.