I cant understand why in the class constructor I can call this function but when called in the test function, it errors out with
E:\Projects\NasuTek-Plugin-Engine\tests\CheckAddonEngine.cpp:64: error: conversion from 'std::auto_ptr<FakeSettableFeaturePlugin>' to 'std::auto_ptr<FakeFeature>' is ambiguous
C++ File
#include <ObjectEngine.h>
#include <memory>
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
class FakeFeature : public PObject {
public:
inline virtual const char *returnSomthingCool() { return "Somthing Cool"; }
};
class FakeFeaturePlugin : public FakeFeature {
public:
inline const char *returnSomthingCool() { return "Somthing Cool From a Plugin Object"; }
inline std::string getName() { return "Fake Feature Plugin Object"; }
};
class FakeSettableFeaturePlugin : public FakeFeature {
public:
inline const char *returnSomthingCool() { return _value; }
inline char *setSomthingCool(const char *value) { _value = const_cast<char *>(value); }
inline std::string getName() { return "Fake Feature Settable Plugin Object"; }
private:
char *_value;
};
typedef ObjectEngine<FakeFeature> FakeFeatureEngine;
class FakeApplication {
public:
inline FakeApplication(){
_engine = new FakeFeatureEngine();
std::auto_ptr<FakeFeature> pluginToAdd (new FakeFeaturePlugin);
_engine->addObject(pluginToAdd); // Essencially what im doing where it errors, both classes inherit FakeFeature
}
inline ~FakeApplication() {
delete _engine;
}
FakeFeatureEngine *_engine;
};
BOOST_AUTO_TEST_CASE(getengineobject) {
FakeApplication *application = new FakeApplication();
FakeFeature &feature = application->_engine->getObject("Fake Feature Plugin Object");
BOOST_CHECK_EQUAL(feature.getName(), "Fake Feature Plugin Object");
BOOST_CHECK_EQUAL(feature.returnSomthingCool(), "Somthing Cool From a Plugin Object");
delete application;
}
BOOST_AUTO_TEST_CASE(addobjecttoengine) {
FakeApplication *application = new FakeApplication();
std::auto_ptr<FakeSettableFeaturePlugin> plugin (new FakeSettableFeaturePlugin);
plugin.get()->setSomthingCool("Bro I Set this to this value ^_^");
application->_engine->addObject(plugin); // This is the line that fails
FakeFeature &feature = application->_engine->getObject("Fake Feature Settable Plugin Object");
BOOST_CHECK_EQUAL(feature.getName(), "Fake Feature Settable Plugin Object");
BOOST_CHECK_EQUAL(feature.returnSomthingCool(), "Bro I Set this to this value ^_^");
delete application;
}
.h File
/**
#file ObjectEngine.h
#brief Header File with Plugin Engine Templates to make adding a plugin interface to your app easier
*/
#ifndef NASUTEKPLUGINENGINE_H
#define NASUTEKPLUGINENGINE_H
#include <boost/ptr_container/ptr_list.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <stdio.h>
#include <string>
class PObject {
public:
inline PObject() {}
virtual std::string getName() = 0;
};
template<typename TObjectType>
class ObjectEngine {
public:
ObjectEngine() {}
~ObjectEngine() {
_objects.clear();
}
void addObject(std::auto_ptr<TObjectType> obj) {
if(boost::is_base_of<PObject, TObjectType>::value) {
_objects.push_back(obj.release());
}
}
TObjectType &getObject(std::string objectName) {
typename boost::ptr_list<TObjectType>::iterator i;
for(i = _objects.begin(); i != _objects.end(); i++) {
if((*i).getName() == objectName) {
return *i;
}
}
throw "Object does not exist.";
}
bool objectExist(std::string objectName) {
typename boost::ptr_list<TObjectType *>::iterator i;
for(i = _objects.begin(); i != _objects.end(); i++) {
if((*i).getName() == objectName) {
return true;
}
}
return false;
}
private:
boost::ptr_list<TObjectType> _objects;
};
#endif // NASUTEKPLUGINENGINE_H
What I'm trying to do is create a plugin engine for my projects while making it reusable, and the C++ file is making sure its working right.
This doesn't look like a problem with Boost Test, per se, but it looks like the line in addobjecttoengine...
std::auto_ptr<FakeSettableFeaturePlugin> plugin (new FakeSettableFeaturePlugin);
...should be...
std::auto_ptr<FakeFeature> plugin(new FakeSettableFeaturePlugin);
...the same as in FakeApplication's constructor. Then there's no conversion to perform at CheckAddonEngine.cpp:64.
Related
I would like to know how to read/write a JSON file using C++.
I will be using this file to store player info & setting for a simple game I'm making.
It's nothing fancy, just a console number guessing game, but I just use it to learn stuff.
I have to know how to read & write specific parts of a JSON.
Using a library, it can be done quite easily:
#include <nlohmann/json.hpp>
#include <iostream>
int main() {
// read file
auto json = nlohmann::json::parse("{\"value1\": \"string\"}");
// mutate the json
json["value1"] = "new string";
// write to a stream, or the same file
std::cout << json; // print the json
}
C++ don't have the built-ins for dealing with json. You can implement your own json data structure, or use one available like nlohmann/json or simdjson
You could create your own parser using pure C++ with the standard library only, but I would advise against.
Using struct_mapping it can be done:
#include "struct_mapping/struct_mapping.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
struct Planet
{
std::string name;
double mass;
bool populated;
};
int main()
{
struct_mapping::reg(&Planet::name, "name");
struct_mapping::reg(&Planet::mass, "mass");
struct_mapping::reg(&Planet::populated, "populated");
Planet planet;
auto stream = std::ifstream("planet.json");
struct_mapping::map_json_to_struct(planet, stream);
planet.name = "Mars";
planet.populated = false;
std::ostringstream out_json_data;
struct_mapping::map_struct_to_json(planet, out_json_data, " ");
std::cout << out_json_data.str() << std::endl;
}
Data file example
{
"name": "Earth",
"mass": 1234,
"populated": true
}
I wrapped boost property tree initialized around classes and macros and it's close to type reflection(but it's still missing a reflection library to finish it off).
It Also supports nesting of types something that alot of so called "fantastic json" libraries fall short of when you get into
the nitty gritty.
So say you have a class what you want to serialize or deserialize in JSON:
I'd write in my cpp
class MyClass: public virtual Algorithm::Interface::ISimpleSerializedType
{
public:
int a;
string b;
// could be simplified further via a variadic macro to generate //SimplePropertyTree
virtual Algorithm::Interface::IPropertyTree SimplePropertyTree(Algorithm::Interface::IPropertyTree& pt, bool toPropertyTree)
{
PSER(a, int)
PSER(b, string)
}
};
The JSON would look something like
{
a : "1"
b :"somestring"
}
My read and write unit tests/snippets would look like this:
//write
MyClass entity;
entity.a = 1;
entity.filename = "test.json";
entity.ToFile();
// read
MyClass entity;
entity.filename = "test.json";
entity.FromFile(); // everything is loaded
code for Algorithm::Interface::ISimpleSerializedType
#ifndef I_SIMPLE_SERIALIZED_TYPE_H
#define I_SIMPLE_SERIALIZED_TYPE_H
#include "IType.h"
#include "IFileSerializer.h"
namespace Algorithm
{
namespace Interface
{
// Class contract that exposes common methods for which to extend
class ISimpleSerializedType : public virtual IType,public virtual IFileSerializer
{
public:
virtual IPropertyTree ToPropertyTree(void){
IPropertyTree pt;
return SimplePropertyTree(pt,true);
};
// method which extracts the values from property tree
virtual void FromPropertyTree(IPropertyTree& pt){
auto tree = SimplePropertyTree(pt,false);
pt = tree._pt;
};
protected:
// need to implement this
virtual IPropertyTree SimplePropertyTree(IPropertyTree& pt,bool ToPropertyTree)
{
return pt;
}
};
}
}
#endif
Code For ITYPE
#ifndef ITYPE_H
#define ITYPE_H
#include <sstream>
#include <string>
#include <vector>
#include <string>
#include "IPropertyTree.h"
#include <fstream>
// macross to simplify streaming property tree
#define __str__(s) #s
#define PADD(s) {\
try\
{\
std::string ss = std::to_string(s);\
std::string key = std::string(__str__(s));\
pt.add(key,ss);\
}\
catch (std::exception ex)\
{\
}\
}
#define PADDS(s) {\
try\
{\
std::string key = std::string(__str__(s));\
pt.add(key,s);\
}\
catch (std::exception ex)\
{\
}\
}
#define PADDBASE(BASE){\
auto st = std::string(__str__(BASE));\
auto pt2 = BASE##ToPropertyTree();\
pt.addPropertyTree(st, pt2);\
}
#define PADDMEMBER(membervar) {\
auto st = std::string(__str__(membervar));\
LOGIT1(st)\
auto _pt = membervar.ToPropertyTree();\
pt.addPropertyTree(st, _pt);\
}
// PGET
#define PGET(VAR,type) { std::string s(__str__(VAR));\
VAR = pt.get<type>(s); }
#define PGETBASE(VAR) {\
try\
{\
auto st = std::string(__str__(VAR));\
auto ptBase##VAR = pt.getChild(st); \
VAR##FromPropertyTree(ptBase##VAR);\
}\
catch (...)\
{\
}\
}
#define PGETMEMBER(membervar) {\
auto st = std::string(__str__(membervar));\
auto pt2 = pt.getChild(st);\
membervar.FromPropertyTree(pt2);\
}
///////////////
/// PGET2
#define PGET2(VAR,type) { std::string s(__str__(VAR));\
VAR = pt._pt.get<type>(s); }
#define PGET2BASE(VAR) {\
try\
{\
auto st = std::string(__str__(VAR));\
auto ptBase##VAR = pt._pt.getChild(st); \
VAR##FromPropertyTree(ptBase##VAR);\
}\
catch (...)\
{\
}\
}
#define PGET2MEMBER(membervar) {\
auto st = std::string(__str__(membervar));\
auto pt2 = pt_pt.getChild(st);\
membervar.FromPropertyTree(pt2);\
}
// PSerialize uses a implied type bool ToPropertyTree and pt
#define PSER(VAR,type) if(toPropertyTree) {\
std::cout << "padd" << std::endl;\
PADD(VAR)\
} else {\
std::cout << "pget" << std::endl;\
PGET(VAR,type)\
}
#define PSERS(VAR) if(toPropertyTree) {\
PADDS(VAR)\
} else {\
PGET(VAR,std::string)\
}
#define PSERBASE(VAR)if(toPropertyTree) {\
PADDBASE(VAR)\
} else {\
PGET2BASE(VAR)\
}
#define PSERMEMBER(membervar)if(toPropertyTree) {\
PADDMEMBER(membervar) \
} else {\
PGET2MEMBER(membervar) \
}
namespace Algorithm
{
namespace Interface
{
// Class contract that exposes common methods for which to extend
class IType
{
public:
IType() {};
// causes problems with hiberlite when you derive it
// from MVC so omitting this
// IType(IType& rhs) { *this = rhs; }
virtual ~IType(){}; // destructor
// methods don't communicate tho the key just the value
// like stl containers returns size of type
virtual size_t size(void){ return sizeof(IType);};
// says the maximum size of the type
virtual size_t max_size(void) { return sizeof(IType); };
virtual void ToString(char* data,size_t& dataSize){ /* not implemented*/ };
virtual void FromString(char* data,size_t& dataSize){};
IType& operator=(const IType& rhs){
std::string s;
IType& rhsRef = const_cast<IType&>(rhs);
size_t size = rhsRef.size();
s.resize(size);
rhsRef.ToString(const_cast<char*>(s.c_str()), size);
FromString(const_cast<char*>(s.c_str()),size);
return *this;
};
// must be friended methods
// istream extraction operators terminated by std::endl for each respective subtype
// ostream extraction operators terminated by std::endl for each respective subtype
// encode the stream to stream with variable name + value name. Useful for key value streams;
virtual IPropertyTree ToPropertyTree(void){
IPropertyTree pt;
return pt;
};
// method which extracts the values from property tree
virtual void FromPropertyTree(boost::property_tree::ptree& typesEncodedInAPropertyTree){
IPropertyTree pt;
pt._pt = typesEncodedInAPropertyTree;
FromPropertyTree(pt);
};
// method which extracts the values from property tree
virtual void FromPropertyTree(IPropertyTree& typesEncodedInAPropertyTree) {
};
// call a serializer here
// method instructs how to write to file by calling the approppriate serializer
virtual void ToFile(void){
};
virtual void FromFile(void) {};
virtual std::string TypeName(void) { return ""; };
protected:
inline bool exist(const std::string& name)
{
std::ifstream file(name);
if (!file) // If the file was not found, then file is 0, i.e. !file=1 or true.
return false; // The file was not found.
else // If the file was found, then file is non-0.
return true; // The file was found.
}
};
}
}
#endif
Code For IPropertyTree
#ifndef I_PROPERTY_TREE_H
#define I_PROPERTY_TREE_H
#include <boost/property_tree/ptree.hpp>
#include <memory>
#include <map>
#include <string>
#include <vector>
#include <iostream>
namespace Algorithm
{
namespace Interface
{
class IPropertyTree
{
const std::string attributePrefix = ".<xmlattr>."; // attribute prefix to reference a attribute within boost property tree
// https://stackoverflow.com/questions/3690436/how-are-attributes-parsed-in-boost-propertytree
std::string BuildAttributeInsertionKey(std::string& key, std::string& attributeKey) { return key + attributePrefix + attributeKey; };
public:
boost::property_tree::ptree _pt; // good reference reading https://theboostcpplibraries.com/boost.propertytree
const IPropertyTree& operator=(const IPropertyTree& pt){
this->_pt = pt._pt;
return *this;};
IPropertyTree(void) :_pt() {};
IPropertyTree(boost::property_tree::ptree& pt) : _pt(pt) {};
// usually only accessed by the serializers don't manually edit this
boost::property_tree::ptree& GetBoostPropertyTree(void) { return _pt; };
#ifdef _WIN32
// key/value get and set
template <class T>
void add(std::string& key, T& value)
{
_pt.put(key, value);
};
#else
template <class T>
void add(std::string key, T value)
{
_pt.put(key, value);
};
#endif
template <class T>
T get(std::string& path) {
return _pt.get<T>(path);
};
// attribute get/set
template <class T>
void addAttribute(std::string& keyName, std::string& attributeKey, T& attributeValue) {
_pt.add(BuildAttributeInsertionKey(keyName, attributeKey), std::to_string(attributeValue));
}
IPropertyTree getChild(std::string& key)
{
return IPropertyTree(_pt.get_child(key));
}
template <class T>
T getAttribute(std::string& keyPath, std::string& attributeName) {
return _pt.get<T>(BuildAttributeInsertionKey(keyPath, attributeName));
}
void addPropertyTree(std::string& keyOfChildTree,IPropertyTree& tree)
{
_pt.add_child(keyOfChildTree,tree.GetBoostPropertyTree());
};
void addAttribute(std::string& keyName,std::string& attributeKey, std::string& attributeValue)
{
_pt.add(BuildAttributeInsertionKey(keyName,attributeKey), attributeValue);
};
};
}
}
#endif
Code For IFileSerializer
#ifndef I_FILE_SERIALIZER_H
#define I_FILE_SERIALIZER_H
#include "IJSONSerialize.h"
#include "IType.h"
#include "../../Tools/Diagnostics/Logger/Logger.h" // this uses LOGIT but you can just replace with std::cout
#include <cstdint>
#include <cstdlib>
#include <string>
namespace Algorithm
{
namespace Interface
{
class IFileSerializer;
// a Serializer for JSON
class IFileSerializer : public virtual Algorithm::Interface::IType
{
public:
std::string filename;
IFileSerializer(void):Algorithm::Interface::IType(),filename(){};
virtual void ToFile(void)
{
std::string msg = TypeName() + "::ToFile()";
LOGIT1(msg)
std::string testJSON(filename);
auto pt = ToPropertyTree();
msg = TypeName() + "::ToFile() calling IJSON serialize";
LOGIT1(msg)
Algorithm::Interface::IJSONSerialize test(testJSON, pt);
msg = TypeName() + "::ToFile() WriteFile";
LOGIT1(msg)
test.WriteFile();
};
virtual void FromFile(void)
{
auto msg = TypeName() + "::FromFile()\n";
LOGIT1(msg)
std::string testJSON(filename);
auto pt = ToPropertyTree();
Algorithm::Interface::IJSONSerialize test(testJSON, pt);
test.ReadFile();
this->FromPropertyTree(test.GetPropertyTree());
};
virtual Algorithm::Interface::IPropertyTree ToPropertyTree(void) { Algorithm::Interface::IPropertyTree pt; return pt;};
// method which extracts the values from property tree
virtual void FromPropertyTree(Algorithm::Interface::IPropertyTree& pt) {};
void ParseServerArgs(char** argv, int argc){
std::string msg2="IFileSerializer::ParseServerArgs";
LOGIT1(msg2)
filename = "config.json";
if(exist(filename))
{
std::string msg = "IFileSerializer::Calling FromFile";
LOGIT1(msg)
FromFile();
}
else
{
std::string msg = "IFileSerializer::Calling ToFile";
LOGIT1(msg)
ToFile(); // write it back so next time you can feed in the json
}
};
}; // end class
}
}
#endif
IJSONSerialize Code
#ifndef IJSONSERIALIZE_H
#define IJSONSERIALIZE_H
#include <string>
#include <vector>
#include <iostream>
#include <boost/property_tree/json_parser.hpp>
#include "IPropertyTree.h"
namespace Algorithm
{
namespace Interface
{
// object that provides facilities to serialize JavaScript Object Notation(JSON)
// citation: https://stackoverflow.com/questions/4586768/how-to-iterate-a-boost-property-tree
class IJSONSerialize
{
IPropertyTree _pt;
std::string _filename;
public:
IJSONSerialize(const std::string& filename, IPropertyTree& pt):_pt(pt),_filename(filename){
};
virtual void WriteFile(void){
try
{
boost::property_tree::json_parser::write_json(_filename, _pt.GetBoostPropertyTree());
}
catch(std::exception ex)
{
std::cerr << "can't write json file " << _filename;
}
};
virtual void WriteAsAString(std::string& outString)
{
std::stringstream ss;
boost::property_tree::write_json(ss, _pt.GetBoostPropertyTree());
outString = ss.str();
};
virtual void ReadFile(void){
try
{
boost::property_tree::read_json(_filename, _pt.GetBoostPropertyTree());
}
catch(const boost::property_tree::json_parser_error &jpe)
{
//do error handling
std::cerr << "can't read json file " << _filename <<jpe.what();
}
};
virtual void ReadFromString(std::string& s){
try
{
std::stringstream ss;
ss << s;
auto pt = _pt.GetBoostPropertyTree(); boost::property_tree::json_parser::read_json(ss, pt);
}
catch(std::exception)
{
}
};
virtual std::string WriteToString(void){
std::stringstream ss;
boost::property_tree::json_parser::write_json(ss,_pt.GetBoostPropertyTree());
return ss.str();
};
// use to retrieve all the values but
virtual IPropertyTree& GetPropertyTree(void){
return _pt;
};
};
}
}
#endif
If any code missing you can find it in my bitbucket crossplatform C++ network template that's built
on top of boost asio. The code is here: https://bitbucket.org/ptroen/crossplatformnetwork/src/master/
And again if you missed the comment and don't want to use LOGIT you can just find and replace with std::cout
Note code above is working but if you study enough their is some tech debt that could be optimized even more like reflection
Anyways hope you find this useful
Hello i have problem of compile my code
i follow http://gamedevgeek.com/tutorials/managing-game-states-in-c/ tutorial
but it fail to compile and i don't know why.
the error msg from visual studio
here is my code
the CGameEngine modify code
#include <vector>
#include "GameState.h"
#include "GameEngine.h"
class GameState;
class GameStateManager
{
public:
GameStateManager(GameEngine* engine, MSG * msg);
~GameStateManager();
void Cleanup();
void ChangeState(GameState* state);
void Update();
bool Running() { return m_running; }
void Quit();
private:
std::vector<GameState *> states;
bool m_running;
GameEngine * m_engine;
MSG *m_msg;
};
#include "GameStateManager.h"
GameStateManager::GameStateManager(GameEngine* engine, MSG * msg)
:m_engine{ engine }, m_msg{ msg }, m_running{ true }
{
}
GameStateManager::~GameStateManager()
{
}
void GameStateManager::Cleanup()
{
while (!states.empty()) {
states.back()->Exit();
states.pop_back();
}
}
void GameStateManager::Quit()
{
m_running = false;
m_msg->message = WM_QUIT;
}
void GameStateManager::ChangeState(GameState* state)
{
if (!states.empty()) {
states.back()->Exit();
states.pop_back();
}
states.push_back(state);
states.back()->Enter(m_engine, m_msg);
}
void GameStateManager::Update()
{
states.back()->Update(this);
}
the CGameState modify code
#include "GameStateManager.h"
class GameState
{
public:
GameState() {}
virtual ~GameState() {}
virtual void Enter(GameEngine * , MSG * ) = 0;
virtual void Update(GameStateManager* game) =0;
virtual void Exit() = 0;
};
one of the state class
#include "MainMenu.h"
class Logo :public GameState
{
public:
Logo();
~Logo();
static Logo* Instance()
{
return &m_Logo;
}
void Enter(GameEngine * engine, MSG * msg);
void Update(GameStateManager* game);
void Exit();
private:
static Logo m_Logo;
};
#include "Logo.h"
Logo::Logo()
{
}
Logo::~Logo()
{
}
void Logo::Enter(GameEngine * engine, MSG * msg)
{
m_GameEngine_Info = engine;
m_msg = msg;
}
void Logo::Update(GameStateManager* game)
{
}
void Logo::Exit()
{
}
i get no compile error when editing the code, but when i try compile it get this error.
You have circular includes. Use include guards and replace
#include "GameStateManager.h"
with
class GameStateManager;
in GameState.h. Move this include into GameState.cpp.
Do similar with #include "GameEngine.h" and #include "GameState.h" in GameStateManager.h and GameStateManager.cpp.
I am completing my c++/CLI wrapper for the following native c++ class:
#ifndef __TV3DENGINE_H__
#define __TV3DENGINE_H__
#pragma once
#include "TV3DMoteur.h"
#include "Input.h"
#include "Area.h"
#include <vcclr.h>
class Engine3D
{
public:
CLTV3DMoteur* clTV3D;
CLInput* clInput;
CLArea* clArea;
CLGlobalVar * clGlobalVar;
Engine3D();
~Engine3D();
void Setup(HWND TVScreenHWND, string PathString);
void UpdateLoop();
void Cleanup();
bool AppStillIdle();
CLTV3DMoteur* GetTV3D();
CLInput* GetInput();
CLArea* GetArea();
CLGlobalVar * GetGlobalVar();
};
#endif
The actual constructor for Engine3D is :
Engine3D::Engine3D()
{
clTV3D = CLTV3DMoteur::getInstance();
clInput = CLInput::getInstance();
clArea = CLArea::getInstance();
clGlobalVar = CLGlobalVar::getInstance();
}
Here is the actual wrapper:
#ifndef __WRAPPER_H__
#define __WRAPPER_H__
#pragma once
#include "TV3DEngine.h"
#include <msclr\marshal_cppstd.h>
public ref class Engine3DWrapper {
Engine3D* m_nativeClass;
public:
Engine3DWrapper() { m_nativeClass = new Engine3D(); }
~Engine3DWrapper() { delete m_nativeClass; }
void Setup(System::IntPtr tvscreen, System::String^ AppPath) {
System::String^ managedPath = AppPath;
m_nativeClass->Setup((HWND)tvscreen.ToInt32(), msclr::interop::marshal_as<std::string>(managedPath));
}
void UpdateLoop() {
m_nativeClass->UpdateLoop();
}
void Cleanup() {
m_nativeClass->Cleanup();
}
bool AppStillIdle() {
return(m_nativeClass->AppStillIdle());
}
protected:
!Engine3DWrapper() { delete m_nativeClass; }
};
#endif
My question is how can I modifiy my Wrapper so I can have access to, exemple, Engine3DWrapper->clGlobalVar->BLABLABLA() where BLABLABLA would be all the different methods defined in the CLGlobalVar c++singleton?
I tried via this technique :
property String ^Name
{
String ^get()
{
return gcnew String(_stu->getName());
}
}
but that seems not possible since I need not to return a defined type.
thanks for your help.
Problem solved.
Here is the corrected Wrapper following Rufflewind suggestion:
#ifndef __WRAPPER_H__
#define __WRAPPER_H__
#pragma once
#include "TV3DEngine.h"
#include <msclr\marshal_cppstd.h>
public ref class Engine3DWrapper {
Engine3D* m_nativeClass;
public:
Engine3DWrapper(System::IntPtr tvscreen, System::String^ AppPath)
{
m_nativeClass = new Engine3D((HWND)tvscreen.ToInt32(), msclr::interop::marshal_as<std::string>(AppPath));
m_TV3D = m_nativeClass->GetTV3D();
m_Input = m_nativeClass->GetInput();
m_Area = m_nativeClass->GetArea();
m_GlobalVar = m_nativeClass->GetGlobalVar();
}
~Engine3DWrapper() {
delete m_nativeClass;
}
void UpdateLoop() {
m_nativeClass->UpdateLoop();
}
void Cleanup() {
m_nativeClass->Cleanup();
}
bool AppStillIdle() {
return(m_nativeClass->AppStillIdle());
}
CLTV3DMoteur* m_TV3D;
CLInput* m_Input;
CLArea* m_Area;
CLGlobalVar* m_GlobalVar;
protected:
!Engine3DWrapper() { delete m_nativeClass; }
};
#endif
using simple Get Method in the native class:
CLGlobalVar *Engine3D::GetGlobalVar()
{
clGlobalVar = CLGlobalVar::getInstance();
return(clGlobalVar);
}
Thanks for you help!
I've got problems passing a member function of a C++ CLI class to a native C callback from a library.
To be precise its the Teamspeak 3 SDK.
You can pass a non member function using the following code without problem:
struct ClientUIFunctions funcs;
/* Initialize all callbacks with NULL */
memset(&funcs, 0, sizeof(struct ClientUIFunctions));
funcs.onConnectStatusChangeEvent = onConnectStatusChangeEvent;
But I need to pass a pointer to a member function, for example:
funcs.onConnectStatusChangeEvent = &MyClass::onConnectStatusChangeEvent;
Any other idea how to use the event within a non static member function is welcome to.
Thanks in advance!
This can only be done via a static class function because C doesn't know anything about the vtable or what object the function is part of. See below for a C++ and Managed C++ example
This could however be a work around, build a wrapper class which handles all the callbacks you need.
#include <string.h>
struct ClientUIFunctions
{
void (*onConnectStatusChangeEvent)(void);
};
class CCallback
{
public:
CCallback()
{
struct ClientUIFunctions funcs;
// register callbacks
my_instance = this;
/* Initialize all callbacks with NULL */
memset(&funcs, 0, sizeof(struct ClientUIFunctions));
funcs.onConnectStatusChangeEvent = sOnConnectStatusChangeEvent;
}
~CCallback()
{
// unregister callbacks
my_instance = NULL;
}
static void sOnConnectStatusChangeEvent(void)
{
if (my_instance)
my_instance->OnConnectStatusChangeEvent();
}
private:
static CCallback *my_instance;
void OnConnectStatusChangeEvent(void)
{
// real callback handler in the object
}
};
CCallback *CCallback::my_instance = NULL;
int main(int argc, char **argv)
{
CCallback *obj = new CCallback();
while (1)
{
// do other stuff
}
return 0;
}
Another possibility would be if the callback supports and void *args like void (*onConnectStatusChangeEvent)(void *args); which you can set from the plugin. You could set the object in this args space so in de sOnConnectStatusChangeEvent you would have something like this:
static void sOnConnectStatusChangeEvent(void *args)
{
if (args)
args->OnConnectStatusChangeEvent();
}
For managed C++ it should be something like this, however I can't get it to compile because it doesn't like the template brackets..
wrapper.h:
using namespace std;
using namespace System;
using namespace System::Runtime::InteropServices;
using namespace System::Text;
namespace Test
{
struct ClientUIFunctions
{
void (*onConnectStatusChangeEvent)(void);
};
public delegate void ConnectStatusChangeEvent(void);
public ref class ManagedObject
{
public:
// constructors
ManagedObject();
// destructor
~ManagedObject();
//finalizer
!ManagedObject();
event ConnectStatusChangeEvent^ OnConnectStatusChangeEvent {
void add(ConnectStatusChangeEvent^ callback) {
m_connectStatusChanged = static_cast<ConnectStatusChangeEvent^> (Delegate::Combine(m_connectStatusChanged, callback));
}
void remove(ConnectStatusChangeEvent^ callback) {
m_connectStatusChanged = static_cast<ConnectStatusChangeEvent^> (Delegate::Remove(m_connectStatusChanged, callback));
}
void raise(void) {
if (m_connectStatusChanged != nullptr) {
m_connectStatusChanged->Invoke();
}
}
}
private:
ConnectStatusChangeEvent^ m_connectStatusChanged;
};
class CCallback
{
public:
static void Initialize(ManagedObject^ obj);
static void DeInitialize(void);
private:
static void sOnConnectStatusChangeEvent(void);
static gcroot<ManagedObject^> m_objManagedObject;
};
}
wrapper.cpp:
#include <string.h>
#include "wrapper.h"
using namespace System;
using namespace Test;
void CCallback::Initialize(ManagedObject^ obj)
{
struct ClientUIFunctions funcs;
// register callbacks
m_objManagedObject = obj;
/* Initialize all callbacks with NULL */
memset(&funcs, 0, sizeof(struct ClientUIFunctions));
funcs.onConnectStatusChangeEvent = sOnConnectStatusChangeEvent;
}
void CCallback::DeInitialize(void)
{
// unregister callbacks
m_objManagedObject = nullptr;
}
void CCallback::sOnConnectStatusChangeEvent(void)
{
if (m_objManagedObject != nullptr)
m_objManagedObject->OnConnectStatusChangeEvent();
}
// constructors
ManagedObject::ManagedObject()
{
// you can't place the constructor in the header but just for the idea..
// create wrapper
CCallback::Initialize(this);
}
// destructor
ManagedObject::~ManagedObject()
{
this->!ManagedObject();
}
//finalizer
ManagedObject::!ManagedObject()
{
CCallback::DeInitialize();
}
gcroot<ManagedObject^> CCallback::m_objManagedObject = nullptr;
int main(array<System::String ^> ^args)
{
ManagedObject^ bla = gcnew ManagedObject();
while (1)
{
// do stuff
}
return 0;
}
I have a class SourceComponent, and its derived class, PeriodicSourceComponent.
Implementations are:
class SourceComponent : public Component
{
protected:
friend class UserInterface;
friend void readInput();
public:
virtual int returnType();
virtual int propagateLogic();
virtual void sourcePropagation(float);
virtual void accept(VisitorSources&);
SourceComponent();
};
and
#include "source_component.h"
class PeriodicSourceComponent : public SourceComponent
{
private:
int frequency;
friend void main();
friend void readInput();
friend class UserInterface;
public:
void sourcePropagation(float);
int returnType();
PeriodicSourceComponent();
};
When I try in some different class/method to do:
SourceComponent* s = new PeriodicSourceComponent;
it won't let me, sayin "a value of type periodicblabla cant be assigned to value of type sourceblabla". Why?
Edit:
Ok, in my main it looks lke this:
#include "source_component.h"
#include "periodic_source_component.h"
void main()
{
SourceComponent* s = new PeriodicSourceComponent;
}
And implementations of both classes:
source.cpp:
#include "source_component.h"
SourceComponent::SourceComponent()
{
outputState = -1;
}
int SourceComponent::propagateLogic()
{
return 1;
}
int SourceComponent::returnType()
{
return 5;
}
and periodic.cpp
#include "periodic_source_component.h"
PeriodicSourceComponent::PeriodicSourceComponent()
{
outputState = 0;
}
int PeriodicSourceComponent::returnType()
{
return 3;
}
void PeriodicSourceComponent::sourcePropagation(float time)
{
float t = time, period;
period = 1000000/frequency;
if(t > period)
{
while(t >= period)
t -= period;
}
if(t <= (period/2))
outputState = 0;
else
outputState = 1;
}
and its not working... (outputState is a member of class Component, base class of SourceComponent)
and the error message: A value of type "PeriodicSourceComponent*" cannot be assigned to a value of type "SourceComponent*".
Important Edit
When I try to compile, the actual compiler error is at PeriodicSourceComponent declaration, it says: "Base class undefined".
and also, I have two other derived classes from SourceComponent, but I don't see how they could interfere with this one..
EDIT 4
Ok so I figured out what causes the error, you were right of course, it something else I didn't post. I have class VisitorSources, heres definition:
#ifndef __VISITOR_SOURCES_H__
#define __VISITOR_SOURCES_H__
#include "component.h"
#include "impulse_source_component.h"
#include "arbitrary_source_component.h"
#include "periodic_source_component.h"
class VisitorSources
{
protected:
VisitorSources();
public:
virtual void visitImpulseSource(ImpulseSourceComponent*);
virtual void visitArbitrarySource(ArbitrarySourceComponent*);
virtual void visitPeriodicSource(PeriodicSourceComponent*);
void visitSource(int, float);
};
#endif
And its implementation is not yet written:
#include "visitor_sources.h"
void visitSource(int type, float time)
{
}
void VisitorSources::visitArbitrarySource(ArbitrarySourceComponent* a)
{
}
When I comment out the entire Visitor class and implementation, the above-mentioned errors are gone for some reason. I have no idea why...
The only error that remains is that when I try to use s->frequency, it says that frequency is not a member of SourceComponent, which is true, but it is a member of PeriodicSourceComponent, which is why I used the cast in the first place..
Finally, here's the Component class, the main class for all almost all other classes in the project :P
#ifndef __COMPONENT_H__
#define __COMPONENT_H__
#include <iostream>
#include <vector>
class Component
{
friend class UserInterface;
friend void readAndSimulate();
protected:
Component();
int numOfInputs;
int numOfOutputs;
std::vector<Component*> inputs;
std::vector<Component*> outputs;
friend void main();
float lengthOfSimulation;
int typeIfSource;
public:
int outputState;
virtual int propagateLogic() = 0;
virtual int returnType();
int beginPropagation();
virtual void sourcePropagation(float);
~Component();
};
#endif
And implementation:
#include "component.h"
#include <conio.h>
Component::Component()
{
}
int Component::beginPropagation()
{
std::vector<Component*>::const_iterator iter = outputs.begin();
for(;iter<outputs.end();++iter)
{
if ((*iter)->outputState == -2)
{
(*iter)->outputState = outputState;
return (*iter)->outputState;
}
}
std::vector<Component*>::const_iterator it = outputs.begin();
int finishedCycle, x;
while(1)
{
finishedCycle = 1;
for(; it < outputs.end(); ++it)
{
x = (*it)->propagateLogic();
if(!x)
finishedCycle = 0;
}
if(finishedCycle) break;
it = outputs.begin();
}
it = outputs.begin();
for(;it<outputs.end();++it)
(*it)->beginPropagation();
}
int Component::returnType()
{
return 0;
}
void Component::sourcePropagation(float)
{
}
Component::~Component()
{
std::vector<Component*>::const_iterator it = inputs.begin();
for(; it < inputs.end(); ++it)
{
if((*it) != NULL)
{
delete *it;
Component* p = *it;
p = NULL;
}
}
it = outputs.begin();
for(; it < inputs.end(); ++it)
{
if((*it) != NULL)
{
delete *it;
Component* p = *it;
p = NULL;
}
}
}
Are you using include guards in all your header files?
Not having them can cause the kinds of problems you're seeing.
Three guesses:
You copied and pasted code between header files and forgot to change the #include guards.
You use precompiled headers and included something before the #include "stdafx.h".
If you use precompiled headers, try deleting the .pch file.