I've wandered into the deep end of the pool here. I've made some good progress but now am just thrashing around. I'm trying to use this fuzzy logic lib in iOS: http://code.google.com/p/fuzzy-lite/
I've got it to compile - what I did was to add both the .cpp & the .h files to my project and changed the suffix on my main viewController to ".mm". I am able to run the fuzzyLite test.h file from within viewDidload (show below). It runs and the test data is displayed.
What I need to do is create a persistent instance of fuzzyLite so I can use it in my app (e.g. be able to address it and then clean up when the app unloads).
I've searched around but haven't understood the discussions/examples of including C++ code in an ObjC project. Can someone show me a way I can move forward with this - wrapping the fuzzyLite code so I can call functions and get results back? Thanks!
EDIT: I've made progress on this using the method detailed here:
http://robnapier.net/blog/wrapping-c-take-2-1-486
One thing I am unclear on is memory cleanup. The dealloc function cleans up the instance of the wrapped CPP instance - but what about memory alloc'ed within the CCP instance? Seems like I need call a method to release that prior to deleting the instance.
ex: the wrapped class has some instance vars of subclasses- is my cleanup function enough to manage the memory properly?
void Bingo::cleanup(){
delete engine;
engine = NULL;
delete health;
health = NULL;
delete energy;
energy = NULL;
}
-header for the wrapped CPP class
#include "fuzzylite/FuzzyLite.h"
namespace fl {
class Bingo {
public:
FuzzyEngine* engine;
OutputLVar* health;
InputLVar* energy;
Bingo();
void Fuzz();
void setInput(float input);
};
}
from the ObjC wrapper:
- (void)dealloc
{
delete _cpp;
_cpp = NULL;
[super dealloc];
}
FuzzyLiteIOSViewController.mm
#include "FuzzyLiteIOSViewController.h"
#include "FuzzyLite.h"
#include "test.h"
#include <limits>
#include "fuzzylite/FunctionTerm.h"
//stuff not shown
- (void)viewDidLoad
{
[super viewDidLoad];
fl::Test* test = new fl::Test();
test->SimpleMamdani();
}
test.h
#ifndef FL_TEST_H
#define FL_TEST_H
namespace fl {
class Test {
public:
static void SimpleMamdani();
};
}
#endif /* FL_TEST_H */
test.cpp
#include "fuzzylite/test.h"
#include "fuzzylite/FuzzyLite.h"
#include <limits>
#include "fuzzylite/FunctionTerm.h"
namespace fl {
void Test::SimpleMamdani() {
FuzzyOperator& op = FuzzyOperator::DefaultFuzzyOperator();
FuzzyEngine engine("simple-mamdani", op);
engine.hedgeSet().add(new fl::HedgeNot);
engine.hedgeSet().add(new fl::HedgeSomewhat);
engine.hedgeSet().add(new fl::HedgeVery);
fl::InputLVar* energy = new fl::InputLVar("Energy");
energy->addTerm(new fl::ShoulderTerm("LOW", 0.25, 0.5, true));
energy->addTerm(new fl::TriangularTerm("MEDIUM", 0.25, 0.75));
energy->addTerm(new fl::ShoulderTerm("HIGH", 0.50, 0.75, false));
engine.addInputLVar(energy);
fl::OutputLVar* health = new fl::OutputLVar("Health");
health->addTerm(new fl::TriangularTerm("BAD", 0.0, 0.50));
health->addTerm(new fl::TriangularTerm("REGULAR", 0.25, 0.75));
health->addTerm(new fl::TriangularTerm("GOOD", 0.50, 1.00));
engine.addOutputLVar(health);
fl::RuleBlock* block = new fl::RuleBlock();
block->addRule(new fl::MamdaniRule("if Energy is LOW then Health is BAD", engine));
block->addRule(new fl::MamdaniRule("if Energy is MEDIUM then Health is REGULAR", engine));
block->addRule(new fl::MamdaniRule("if Energy is HIGH then Health is GOOD", engine));
engine.addRuleBlock(block);
for (fl::flScalar in = 0.0; in < 1.1; in += 0.1) {
energy->setInput(in);
engine.process();
fl::flScalar out = health->output().defuzzify();
(void)out; //Just to avoid warning when building
FL_LOG("Energy=" << in);
FL_LOG("Energy is " << energy->fuzzify(in));
FL_LOG("Health=" << out);
FL_LOG("Health is " << health->fuzzify(out));
FL_LOG("--");
}
}
It's basically not possible to answer your question given the information provided. Your question is about the cleanup method of the Bingo class, but instances of Bingo (either on the stack or the heap) appear nowhere in your code excerpts. Likewise, you state that you are cleaning up a "wrapped CPP instance" but it's referenced nowhere else. It does appear that you have leaks in your Test::SimplMamdani method -- you new a bunch of objects there that don't [at least in the revealed code] have any corresponding deletes. Similarly, in your FuzzyLiteIOSViewController::viewDidLoad method you create a Test instance on the heap without a corresponding delete. I'm assuming that there's no autoptr stuff going on under the hood in your C++ code.
UPDATED to provide additional information:
Based upon your comment, you need to review the basic language structure of C++. The basic rule is that you'll need to delete anything that you new. Clean up for the Bingo class should be performed in the destructor (a C++ construct to Objective-C's dealloc). Your Bingo class should look something more like:
Bingo.h:
namespace fl {
class Bingo {
public:
Bingo();
virtual ~Bingo();
void Fuzz();
void setInput(float input);
FuzzyEngine* engine;
OutputLVar* health;
InputLVar* energy;
protected:
private:
};
}
Bingo.cpp:
using namespace fl;
Bingo::Bingo() {
}
Bingo::~Bingo() {
if (engine) {
delete engine;
}
if (health) {
delete health;
}
if (energy) {
delete energy;
}
}
When you delete a Bingo instance, the destructor will be called and Bingo's member variables will be disposed.
Arguably your member variables (engine, health, and energy) should be private in scope and exposed via public-scoped getters and setters.
Grab a copy of Bjarne Stroustrup's C++ reference and give it a quick perusal, or use an online get-up-and-going guide like this one.
Related
I am writing a CLI/C++ wrapper for a C-library in order to use it in C#. It must be said, I only have access to the C header file and the .lib of the C-library, not the source code.
Some of the functions I am trying to wrap are returning opaque handles, such as:
typedef struct SanEvent_s *SanEvent;
typedef struct SanValue_s *SanValue;
Returning objects of this type on the C# end seems like trouble to me, as I don't know the implementation of the struct (I tried returning the SanEvent type in the C++ wrapper but on the C# end that type is not accessible due to "protection level" or whatever it said). My plan at the moment is therefore to write some helper functions, which instead just return an integer which represents an, for example, San Event in a list or something. The list would be kept in the managed C++ wrapper, where I can actually manage the San Event type.
My problem is, I don't really know how to do this with this type of type.
This:
using System::Collections::Generic::List;
namespace Wrapper {
public ref class Analytics
{
private:
static List<SanEvent^>^ events = gcnew List<SanEvent^>();
}
}
Gives me the errors: handle to handle, pointer, or reference is not allowed
The right hand side also complains about expected type specifier + the same error as above.
Can anyone give me some tips on how I could tackle this issue neatly and efficiently? My List implementation is not carved in stone, and I am open to better suggestions.
Let's imagine following SanEvent declaration
struct SanEvent_s
{
int test;
};
typedef SanEvent_s *SanEvent;
And following C++ API to work with such event:
SanEvent GetEvent()
{
auto e = new SanEvent_s();
e->test=42;
return e;
}
int UseEvent(SanEvent pEvent)
{
return pEvent->test;
}
All this code contained in static library project (fully native, no CLR).
Then we have C++/CLI project to wrap this static lib.
Here we have wrapper for event itself:
#include "./../CppLib/SanEvent_s.h"
public ref class SanEventWrapper: Microsoft::Win32::SafeHandles::SafeHandleZeroOrMinusOneIsInvalid
{
public:
static SanEventWrapper^ GetWrapper()
{
return gcnew SanEventWrapper(GetEvent());
}
internal:
SanEventWrapper(SanEvent event):SafeHandleZeroOrMinusOneIsInvalid(true)
{
this->e = event;
this->handle = System::IntPtr(event);
}
int UseWrapper()
{
return ::UseEvent(this->e);
}
protected:
bool ReleaseHandle() override
{
//todo: release wrapped event
return true;
}
private:
SanEvent e;
};
And another class which uses such a wrapper
public ref class SanEventConsumer
{
public:
int ConsumeEvent(SanEventWrapper^ wrapper)
{
return wrapper->UseWrapper();
}
};
And finally, how to use all this from C#:
var wrapper = SanEventWrapper.GetWrapper();
var consumer = new SanEventConsumer();
var res = consumer.ConsumeEvent(wrapper);
Console.WriteLine(res);
This should print 42;
Notes:
Notes:
this is a very simplified sample. It should be adapted ytrin accordance with semantics of 'SanEvent' struct as well as with respect of requirements of SafeHandle documentation (https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.safehandle?view=netframework-4.8 and https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.safehandles.safehandlezeroorminusoneisinvalid?view=netframework-4.8)
you should decide if your wrapper will own the SunEvent object or not and implement ReleaseHandle and Dispose accordingly to this.
you may consider to use another base class from this list https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.safehandles?view=netframework-4.8 instead of 'SafeHandleZeroOrMinusOneIsInvalid' or even make direct inhernitance from SafeHandle.
you can even think about dropping SafeHandle-related stuff at all and making the simple wrapper by your own, but it can give some surprises in connection with GC.
depending of the semantics of the SunEvent you may be also need to implement factory to guarantee that you always return to the managed code the same instance of wrapper for all equals values of raw native pointer.
Here's something similar to what #Serg has above, but explicitly goes with the idea that you have NO IDEA in the C# world what's inside the object.
So if you have a C++/CLI library made in VS, you get this in the .h file:
#pragma once
#include <cstdint>
using namespace System;
namespace CppCliLibrary {
public ref class Class1
{
public:
static IntPtr getOpaqueInstance(int32_t argument);
static void useOpaqueInstance(IntPtr obj);
static void freeOpaqueInstance(IntPtr obj);
};
}
Like above, using IntPtr to represent a pointer to "whatever". The corresponding .cpp file is this:
#include "pch.h"
#include "CppCliLibrary.h"
#include <string>
#include <iostream>
namespace CppCliLibrary
{
class OpaqueCppClass
{
public:
OpaqueCppClass(int32_t arg)
: m_int(arg) { }
int32_t m_int;
};
}
IntPtr CppCliLibrary::Class1::getOpaqueInstance(int32_t argument)
{
return IntPtr(new OpaqueCppClass(argument));
}
void CppCliLibrary::Class1::useOpaqueInstance(IntPtr obj)
{
CppCliLibrary::OpaqueCppClass* deref = reinterpret_cast<CppCliLibrary::OpaqueCppClass *>(obj.ToPointer());
std::cout << "Contents of class are: " << deref->m_int << std::endl;
}
void CppCliLibrary::Class1::freeOpaqueInstance(IntPtr obj)
{
CppCliLibrary::OpaqueCppClass* deref = reinterpret_cast<CppCliLibrary::OpaqueCppClass*>(obj.ToPointer());
std::cout << "Deleting class with contents: " << deref->m_int << std::endl;
delete deref;
}
Then in the C# file you have this:
namespace CsCoreConsole
{
class Program
{
static void Main(string[] args)
{
// Get an instance
var instance = CppCliLibrary.Class1.getOpaqueInstance(52);
// Use it
Console.WriteLine("Got an instance we're using");
CppCliLibrary.Class1.useOpaqueInstance(instance);
Console.WriteLine("Freeing it");
CppCliLibrary.Class1.freeOpaqueInstance(instance);
// Add a bunch to a list
List<IntPtr> opaqueInstances = new List<IntPtr>();
for(int i = 0; i < 5; i++)
{
opaqueInstances.Add(CppCliLibrary.Class1.getOpaqueInstance(i * 10));
}
// Use them all
foreach(var cur in opaqueInstances)
{
CppCliLibrary.Class1.useOpaqueInstance(cur);
}
// Delete them all
foreach (var cur in opaqueInstances)
{
CppCliLibrary.Class1.freeOpaqueInstance(cur);
}
}
}
}
Of course the C# project needs to reference the C++/CLI one, but you get the idea here. The C++/CLI is a factory (nothing more, nothing less) for IntPtr and it can use it as well, because to C# it's opaque. C# knows of nothing more than IntPtr.
The idea from Serg is to wrap it more, in a type-safe way. Sure, that can work, but this is the "even more raw" variant, if you want to put it "directly" into a List<>
In my simple Arduino project, in order to keep things tidy, I decided to create a "Mode Manager" that will handle passing between one mode and another. The basic concept is that each time I want to change the mode, then it will instantiate the next mode and replace the previous one.
Please note that I have 12+ years experience in OOP and Java / Scala, but no experience whatsoever in C++, just the stuff needed to make an Arduino do its stuff without too many structures.
With some studying I managed to create the following "interface" structure:
File: modes/ModeManager.h. This should keep a reference to the current mode, and delegate to it the looping and instantiating the next mode (each mode will know which is the next in line)
#ifndef __MODE_MANAGER__
#define __MODE_MANAGER__
#include <stdint.h>
#include "modes/Mode.h"
class ModeManager {
private:
Mode *mode;
public:
ModeManager();
~ModeManager() {};
virtual void loop(uint8_t voltage);
};
#endif
File: modes/Mode.h is the actual "mode" that runs the real loop function of the program. It also handles instantiating the next mode
#ifndef __MODE__
#define __MODE__
#include <stdint.h>
class Mode {
public:
Mode() {}
virtual ~Mode() {}
virtual void loop(uint8_t voltage) = 0;
virtual void getNext(Mode * target) = 0;
};
#endif
File: modes/ModeManager.cpp
#include "ModeManager.h"
#include <stdint.h>
#include <Arduino.h>
#include "modes/Mode.h"
#include "modes/DummyMode.h"
#define VOLTAGE_NEXT_MODE 5
ModeManager::ModeManager() {
DummyMode cmode = DummyMode();
mode = & cmode; // I'm not sure how this should actually be done
}
void ModeManager::loop(uint8_t voltage) {
if (voltage == VOLTAGE_NEXT_MODE) {
Serial.println("Switching to next mode");
mode->getNext(mode);
} else {
Serial.println("Calling mode loop");
mode->loop(voltage); // From here, nothing.
}
}
File: modes/DummyMode.h
#ifndef __DUMMY_MODE__
#define __DUMMY_MODE__
#include "modes/Mode.h"
class DummyMode : public Mode {
public:
DummyMode();
~DummyMode() {}
virtual void loop(uint8_t voltage);
virtual void getNext(Mode * target);
};
#endif
File: modes/DummyMode.cpp
#include "modes/DummyMode.h"
#include <Arduino.h>
DummyMode::DummyMode() {
Serial.println("Initialization of dummy mode");
}
void DummyMode::loop(uint8_t voltage) {
Serial.print("Voltage: ");
Serial.println(voltage);
}
void DummyMode::getNext(Mode * target) {
DummyMode nextMode = DummyMode();
target = &nextMode;
}
and finally my main.cpp
#include <Arduino.h>
#include "modes/ModeManager.h"
#include "modules/memory.h"
#include "modules/monitor.h"
ModeManager * modeManager;
void setup() {
pinMode(A0, INPUT);
Serial.begin(9600);
Serial.println("Init");
ModeManager mm = ModeManager();
modeManager = & mm;
}
void loop(void) {
uint8_t voltage = map(analogRead(A0), 0, 1024, 0, 5);
modeManager->loop(voltage);
}
Now, theoretically I see no reason why this should not work. In practice I'm 99.9% sure I am doing something wrong with initializations and pointers.
When I try to run this code, I get the following serial out:
Init
Initialization of dummy mode
Calling mode loop
Which means that it freezes at the first iteration of the loop, right before calling mode->loop(voltage);
Can anyone point me in the right direction? Again, I have really no experience of C++, and my knowledge of how to make this structure came from various online resources of C++ programming, including some answers here so please bear with me
Here:
DummyMode cmode = DummyMode();
you are creating a DummyMode instance cmode with automatic lifetime (commonly referred to as on the stack).
You then take the address and assign that to another variable:
mode = & cmode; // I'm not sure how this should actually be done
Since cmode is an object with automatic lifetime it will be destroyed when the program leaves the scope in which it was created. As a result the pointer stored in mode will be dangling and referring to an object that no longer exists. Dereferencing it will trigger undefined behaviour.
It looks like your intention is to create the object with dynamic lifetime.
You can do that with the following:
mode = new DummyMode();
Though then you are responsible for ensure the object is destroyed when it is no longer needed.
That would be done with delete:
delete mode;
In more idiomatic/modern C++ it is typically to use smart pointers to manage the lifetime of such objects and not manually call delete. I see that C++'s standard library is not available for Arduino, but there does seem to be a smart pointer available: https://www.arduino.cc/reference/en/libraries/arxsmartptr/
I would recommend having a good look at using that to have a much easier time avoiding memory leaks.
First of all, sorry for the title. I didn't know exactly how to give name to the situation I'm facing.
I am developing a project in C++ that will run over QNX (so answers that recur to Windows libraries are not good).
I have one class that holds and manipulates all my data, and a few other classes that are responsible for dealing with my UI.
The UI manipulating classes include my data class, and when they are initialized, they all get a pointer to the same data object (each one uses different parts of it, though). And the normal flow of the program is the UI receiving events from the user, and then making calls to the data class and updating itself, according to the data class replies. That all works just fine.
The problem is, sometimes it might happen that this data class object receives calls from other sorts of external events (let's say a call from a class responsible for communication), asking it to change some of it's values. After doing so, it would have to update the UI (thus, having to make a call to the UI classes).
The actual objects to all the classes (UI and data) are contained by the "main" class. But as the UI classes include the data class to be able to call it's methods, the data class including UI classes in order to be able to call their methods would fall into mutual inclusion.
The problem resumes, in a very simplistic way (I am just trying to give a visual example of the information flow), to something like this:
main.cpp
#include "interface.h"
#include "data.h"
Data data_;
Interface interface_;
// Initialize all data from files, etc
data_.Init();
// Call the interface that will use all of this data
interface_.Init(&data_);
while(1);
interface.h
#include "data.h"
class Interface
{
Data *data_;
void Init(Data *data);
void ReceiveEvent();
void ChangeScreen (int value);
};
interface.cpp
#include "interface.h"
void Interface::Init(Data *data)
{
// Get the pointer locally
data_ = data;
}
// Function called when a (for example) a touch screen input is triggered
void Interface::ReceiveEvent()
{
ChangeScreen(data_->IncreaseParam1());
}
void Interface::ChangeScreen (int value);
{
// Set the value on screen
}
data.h
class Data
{
int param 1;
void Init();
int IncreaseParam1();
void ReceiveExternalEvent();
};
**data.cpp"
#include "data.h"
void Data::Init()
{
// The value actually come from file, but this is enough for my example
param1 = 5;
}
int IncreaseParam1()
{
param1 += 5;
return param1;
}
// This is called from (for example) a communication class that has a
// pointer to the same object that the interface class object has
void ReceiveExternalEvent()
{
IncreaseParam1();
// NOW HERE IT WOULD HAVE TO CALL A METHOD TO UPDATE THE INTERFACE
// WITH THE NEW PARAM1 VALUE!
}
I hope I made myself clear enough.
Can someone please give me ideas on how to deal with this situation?
Thanks a lot in advance!
Both Data and Interface are singletons. You expect to only have one instance of each class in existence. So:
Class Data {
public:
static Data *instance;
Data()
{
instance=this;
}
// Everything else that goes into Data, etc...
};
Class Interface {
public:
static Interface *instance;
Interface()
{
instance=this;
}
// Everything else that goes into Data, etc...
};
Now, ReceiveExternalEvent() will simply invoke Data::instance->method() and/or Interface::instance->method(), and so on...
This is a classical singleton design pattern.
Also, you might find some additional Google food of likely interest to you: "model view controller" and "mvc".
I guess it'll be easiest if I give an example of what I'm trying to achieve.
Let's say I'd like to implement a unit testing environment, in which implementing a new unit test would involve deriving from a given base class and (possibly) following guidlines involving putting additional macros. Such new test would then be automatically added to list of tests, ran one after another at some point. Two things however:
I'm trying to make creating each new test as quick and easy as possible, especially when it comes to modifying files other than the files with the test itself. A perfect situation would be such, that implementing a new test wouldn't require touching any other files in the project. This is achievable with singletons and possibly CRTP, but now comes point number 2,
The target is an MCU with limited amount of RAM (ROM in general is not a problem) and I'd like to be able to run the tests directly on the target platform. Because of this, static objects occupying memory throughout the entire application lifetime are not acceptable. Instead, I'd like to be able to create and delete each test separately only at the time it needs to be ran.
Basically, the problem comes down to a way of automatically registering derived types - or creator methods - to a factory with minimum RAM overhead (I'm assuming there will be some, i.e. at least pointers to said methods).
Sorry for no code samples, but there's really nothing to show here without already committing to one given implementation.
Could you create a static/global vector of function pointers. These would be pointers to creator/factory functions for each test class. The factory functions return pointers to the base test class. I was going to try to write it out, but I think code is easier to write and understand.
class TestBase
{
public:
static char registerTest(<function ptr type> creator) {
testCreators.push_back(creator);
return 1;
}
static void runTests()
{
for (auto creator : testCreators)
{
auto newTestClass = creator();
newTestClass->tests();
delete newTestClass;
}
}
private:
void tests() = 0;
std::vector<function ptr type> testCreators;
};
Then the derived class.
class SpecificTest : public TestBase
{
// Pretend test code is here.
private:
static char dummy;
};
// Plan old C function. Need to establish naming conventions so as
// not to get multiple symbol errors during linking. Kind of fragile.
TestBase* specificTestCreator()
{
return new SpecificTest();
}
In the .cpp file for SpecificTest
char SpecificTest::dummy = TestBase::registerTest(specificTestCreator);
I have tried to compile or run this, but I think it's fundamentally sound.
I've created an example based on the answer provided by Michael, compiled and ran it. Posting code below.
TestBase.h:
#ifndef TESTBASE_H_
#define TESTBASE_H_
#include <vector>
class TestBase {
public:
TestBase();
virtual ~TestBase();
static void RunAllTests();
protected:
virtual void test() = 0;
static char addTestCreator(TestBase* (*creator)());
private:
static std::vector<TestBase* (*)()> &getTests();
};
#endif /* TESTBASE_H_ */
TestBase.cpp
#include "TestBase.h"
TestBase::TestBase() {
}
TestBase::~TestBase() {
}
char TestBase::addTestCreator(TestBase* (*creator)())
{
getTests().push_back(creator);
return 0;
}
void TestBase::RunAllTests()
{
for(std::vector<TestBase* (*)()>::iterator it = getTests().begin(); it != getTests().end(); it++)
{
TestBase *t = (*it)();
t->test();
delete t;
}
}
std::vector<TestBase* (*)()> &TestBase::getTests()
{
static std::vector<TestBase* (*)()> v;
return v;
}
ConcreteTest1.h:
#ifndef CONCRETETEST1_H_
#define CONCRETETEST1_H_
#include "TestBase.h"
class ConcreteTest1: public TestBase {
public:
ConcreteTest1();
virtual ~ConcreteTest1();
protected:
void test();
private:
// both here can be expanded with a macro to make it
// easier as they'll be same for all derived classes
static char dummy;
static TestBase *creator();
};
#endif /* CONCRETETEST1_H_ */
ConcreteTest1.cpp:
#include "ConcreteTest1.h"
#include <iostream>
// can be expanded with a macro
char ConcreteTest1::dummy = TestBase::addTestCreator(ConcreteTest1::creator);
// can be expanded with a macro
TestBase* ConcreteTest1::creator()
{
return new ConcreteTest1();
}
ConcreteTest1::ConcreteTest1()
{
std::cout << "Creating test 1" << std::endl;
}
ConcreteTest1::~ConcreteTest1()
{
std::cout << "Deleting test 1" << std::endl;
}
void ConcreteTest1::test()
{
std::cout << "Running test 1" << std::endl;
}
Similarly ConcreteTest2.cpp/.h.
Invoked from main with:
TestBase::RunAllTests();
Output is:
Creating test 1
Running test 1
Deleting test 1
Creating test 2
Running test 2
Deleting test 2
which is exactly what I've wanted to achieve.
Coming from Java to C++ I'm attempting to understand abstraction through object orientation.
To put this into a practical example, I am developing a small game using the SFML library for graphics. However this question does not relate to that, simply think of it as background info. Anyway, the way the game works is to process through a number of different states. In this case 2:
The Menu State: The menu of the game is drawn and the game will begin here.
The Game State: This state controls the game, will update entities and draw them.
In order to do this I have created the following classes:
GameStateManager.h
#ifndef GAMESTATEMANAGER_H
#define GAMESTATEMANAGER_H
#include <SFML/Graphics.hpp>
#include <iostream>
#include "GameState.h"
class GameStateManager
{
public:
// Constructor
GameStateManager();
// State variables
static const int NUMGAMESTATES = 2;
static const int MENUSTATE = 0;
static const int GAMESTATE = 1;
// Public Functions
void set_state(int state);
void update();
void draw(sf::RenderWindow &win);
void input(sf::Event event);
private:
// Array of gamestates
GameState game_states[];
// The current state
int current_state;
// Private functions
void load_state(int state);
void unload_state(int state);
};
#endif
GameState.h
#ifndef GAMESTATE_H
#define GAMESTATE_H
#include <iostream>
#include <SFML/Graphics.hpp>
#include "GameStateManager.h"
class GameState
{
protected:
GameStateManager gsm;
public:
virtual void init() = 0;
virtual void update() = 0;
virtual void draw(sf::RenderWindow &win) = 0;
virtual void input(sf::Event event) = 0;
};
#endif
Now you may have noticed the Array of GameStates in Game State Manager? This provides an error to which I do not understand: zero-sized array. Does this mean initialization needs to be made within the header file? Further to this point the compiler mentions an Array of Abstract class isn't allowed?
The second issue is that the field gsm in the abstract GameState class does not recognize and brings up yet another error: Missing type specifier.
Now to complicate things further I have the following class: MenuState. This class is meant to extend GameState.
MenuState.h
#ifndef MENUSTATE_H
#define MENUSTATE_H
#include "GameState.h"
class MenuState: public GameState
{
public:
MenuState(GameStateManager gsm);
void init();
void update();
void draw(sf::RenderWindow &win);
void input(sf::Event event);
private:
sf::Texture title_texture;
sf::Sprite title_sprite;
};
#endif
As mentioned this class will control the menu of the game.
Implementing GameStateManager is done as follows:
GameStateManager.cpp
/*
* GameState Manager will take care of the various states of the game.
* In particular there will be two states: Menu or Ingame. GameStateManager
* will load and unload each state as needed.
*
* Author: Ben Euden
* Date: 2/5/2014
*/
#include "GameStateManager.h"
// Class Constructor
GameStateManager::GameStateManager()
{
game_states = game_states[NUMGAMESTATES];
current_state = MENUSTATE;
load_state(current_state);
}
/*
* Load the current game by creating and initialising the state
* then storing it in the game_states array.
* #Param state The state we wish to load.
*/
void GameStateManager::load_state(int state)
{
if(state == MENUSTATE)
game_states[state] = MenuState(this);
//if(state == GAMESTATE)
//game_states[state] = MainGameState(this); // Not implemented yet.
}
/*
* Unload the state we loaded with load_state
*/
void GameStateManager::unload_state(int state)
{
game_states[state] = NULL;
}
void GameStateManager::set_state(int state)
{
unload_state(state);
current_state = state;
load_state(state);
}
void GameStateManager::update()
{
try{
game_states[current_state].update();
}
catch(int e)
{
std::cout << "Exception occured during update of game state" << e << std::endl;
}
}
void GameStateManager::draw(sf::RenderWindow &win)
{
try{
game_states[current_state].draw(&win);
}
catch(int e)
{
std::cout << "Exception occured when trying to draw gamestate: " << current_state << "Exception number: " << e << std::endl;
}
}
void GameStateManager::input(sf::Event event)
{
game_states[current_state].input(event);
}
And MenuState as follows:
/*
* This class extends the Game State header and will deal with the menu of the game
* this includes drawing the correct text to the screen, moving the selector and
* either exiting, bringing up about or starting the game.
*
* Author: Ben Euden
* Date: 2/5/2014
*/
#include "MenuState.h"
MenuState::MenuState(GameStateManager gsm)
{
gsm = gsm;
init();
}
void MenuState::init()
{
title_texture = sf::Texture();
title_texture.loadFromFile("sprites/Title.png");
title_sprite = sf::Sprite();
title_sprite.setTexture(title_texture);
title_sprite.setPosition(512, 200);
}
void MenuState::update(){}
void MenuState::draw(sf::RenderWindow &win)
{
win.draw(title_sprite);
}
void MenuState::input(sf::Event event)
{
}
Please ignore inplemented methods and positionings. At this point I began to attempt to compile the project (I'm using Visual Studio) when the errors appeared.
Now in understand that the MainGameState hasn't been implemented yet but even with MenuState I'm sure I'm missing something vital here as I am still learning C++. With this in mind also please excuse any breakage of conventions etc again I am learning so feel free to correct me, it is better I learn the right way now rather than develop bad habits.
In Summary I'd like to understand why I am receiving the following errors:
protected:
GameStateManager gsm;
This produces the error: missing ';' before gsm.
GameState game_states[];
Produces the errors of: zero-size array, array of abstract class not allowed.
I believe if I fix these the rest will sort themselves out.
Thank you for your patience, time and assistance with this.
Euden
To be short: you don't know any basics of C++, and as a beginner, you should really aproach it as a totally different language than Java or C, so you should stop your project right now and find a good book for C++ beginners. Don't try to mix your Java knowledge and just fill the gaps to reach C++ knowledge, it will not work because even if the syntaxe is close, they are widely different beasts.
I always recommend learning C++ as a new and different language, whatever your background. Right now you are doing big errors that shows you're on the wrong path to learn C++. You should get back to basic tutorials (I'm not trying to be harsh, you really need to learn the basics before even managing to compile this code).
You use of arrays and members like if they were references shows your lack of understanding of "value semantic" and several other basic concepts which are must-known of C++ usage.
For example, if I have
class A
{
int k = 42; // C++11
};
Here a A object will contain a k object. What I mean is that k is not a pointer to an int, it's the actual value, within memory allocated into the A object.
So if I have
A my_object; // object on the stack
Then my_object is an object taking the size of an int. So if I do:
class B
{
int u;
A a;
};
Then an instance of B will actually be the size of a A object, plus the size of an int. B objects will contain all these data in a single block of memory.
So when you do:
class GameState
{
protected:
GameStateManager gsm;
What you actually do here is that you build a full GameStateManager into any GameState object. Yes, gsm is not a reference, it's the full object.
What you should do here is either use a c++ reference (if the game manager should never change) or use a pointer (or a smart poitner if there is ownership involved).
I see a lot of other problems, like your array member into GameStateManager have absolutely not the same meaning than in Java. Basically, you're note coding in C++ here. (and you should use either std::vector or std::array but your GameState are dynamic so it would vector or array of pointers - or even map or another container).
As there is too much to point, I should get to the core point:
Whatever the language that you have learnt before, even C or Java which are related, never ever assume you know anything of C++ yet, you absolutely don't. You need to approach it as a beginner. Learn it as a very new language.
And make sure you read actually good material as the list provided there. It's extremely easy to learn bad practice online about C++, unfortunately (but it gets better).
Also, you might want to read this: https://softwareengineering.stackexchange.com/questions/76675/how-can-a-java-programmer-make-the-most-of-a-new-project-in-c-or-c/76695#76695
By the way, a related recommendation: read "SFML Game Development" book for example of simpler and safer (and C++-idiomatic) ways to do what you are trying to achieve here.
Another side recommendation would be to avoid using "manager" in your type names, it only makes things hard to understand and design.
The "zero-size array" error is caused by GameState game_states[];.
In C++ you have to specify the array size at declaration time, either by specifically writing the size or direct initializing it.
Example:
GameState game_states[ ]; // Error, compiler can't know how much memory to reserve for this.
GameState game_states[4]; // OK, explicit size given, compiler will reserve enough memory for 4 `GameState` objects.
GameState game_states[ ] = { GameState( ), GameState( ) }; // OK, direct initialization, compiler will reserve enough memory for 2 `GameState` object.
In your case it should be:
GameState game_states[ NUMGAMESTATES ];
And you should drop the following line from GameStateManager constructor:
game_states = game_states[NUMGAMESTATES]; // Meaningless in C++.
"Array of Abstract class isn't allowed" arises from this declaration also, the problem is C++ differs from Java here. In C++ this declares a variable which is a GameState instance, which is not allowed because GameState has pure virtual methods and as so can't be instantiated ( Just as Java abstract classes can't be newed ). To achieve this polymorphic behavior in C++ you have to use pointers or references, which is what Java uses implicit for you.
Fixing this should give you:
GameState * game_states[ NUMGAMESTATES ];
"missing ';' before gsm" is happening just because the compiler couldn't compile GameStateManager, fixing the bugs I mentioned should solve this.
Few tips:
Think of variables in C++ as ints from Java, even for types you've declared yourself. Which means they are instantiated just by declaring then ( no new needed ) and they are copied when assigned to another variable. ( no reference semantics by default as Java )
Look for good C++ books/tutorials as you don't seem to understand some very important basic concepts from C++.