What I wish to do is have a class that contains a map of function pointers of a second class, but the name of the second class should not matter (cannot be hard coded into the first class) I would really like to be able to implement this WITHOUT using macros. I have followed the examples from learncpp.com on function pointers, but when passing them between classes I am really lost! My attempt is below:
#include <map>
class Class1;
typedef double(Class1::*memFunc)();
class Class1
{
private:
std::map<std::string, memFunc> funcMap;
public:
void addFunc(std::string funcName, memFunc function)
{
funcMap.insert(std::pair<std::string, memFunc>(funcName, function));
}
};
class MyClass
{
public:
MyClass()
{
//How do I add member function getValue() to Class1?
class1.addFunc("new function", getValue());
}
double getValue()
{
return 0;
}
private:
Class1 class1;
};
The name of the class is a part of the type of the function pointer, which becomes part of the map's type, which becomes part of MyClass. Depending on how strong is the requirement "cannot be hard coded", perhaps a template would be sufficient?
#include <string>
#include <map>
template<typename T>
class Class1
{
typedef double(T::*memFunc)();
std::map<std::string, memFunc> funcMap;
public:
void addFunc(std::string funcName, memFunc function)
{
funcMap.insert(std::pair<std::string, memFunc>(funcName, function));
}
};
class MyClass
{
public:
MyClass()
{
class1.addFunc("new function", &MyClass::getValue);
}
double getValue()
{
return 0;
}
private:
Class1<MyClass> class1;
};
int main()
{
MyClass mc;
}
Related
I have a sprite class, which has a templatised data member. It holds an object, which has a pointer to this specialised sprite template class.
That object requires a forward declaration of my sprite class, but since sprite is a template class, I need to include the full header. Therefore I get a cyclic dependancy which I am unable to figure out
Sprite.h
#include "myclass.h"
template<typename SpriteType, typename = typename std::enable_if_t<std::is_base_of_v<sf::Transformable, SpriteType> && std::is_base_of_v<sf::Drawable, SpriteType>>>
class Sprite {
public:
SpriteType s;
myclass<SpriteType>;
Sprite() {
}
auto foo() {
return s;
}
private:
};
myclass.h
#include "Sprite.h"
//a sprite of type T, is going to create a myclass<Sprite<T>>, a pointer of the Sprite<T> is held in myclass.
template<typename T>
class myclass
{
public:
std::shared_ptr<Sprite<T>> ptr;
myclass() {
}
private:
};
How could I solve this cyclic dependency?
So in summary:
-Sprite is a template class.
-Sprite holds an object to another class. This other class holds a pointer to my this templated sprite class.
-This gives me a cyclic dependency, since both classes are now templates, and need to have their implementations written in their header files.
Simplified decoupling, based on #Taekahns solution.
template<typename T>
class myclass
{
public:
std::shared_ptr<T> ptr;
myclass() {
}
private:
};
template<typename SpriteType, typename = typename std::enable_if_t<std::is_base_of_v<sf::Transformable, SpriteType> && std::is_base_of_v<sf::Drawable, SpriteType>>>
class Sprite {
public:
SpriteType s;
// DO NOT PASS SpriteType here, put the whole Sprite<SpriteType>
myclass<Sprite<SpriteType>> t;
Sprite() {
}
auto foo() {
return s;
}
private:
};
One of the great thing about templates is breaking type dependencies.
You could do something like this. Simplified for readability.
template<typename T>
class myclass
{
public:
std::shared_ptr<T> ptr;
myclass() {
}
private:
};
template<typename SpriteType, typename = std::enable_if_t<std::is_base_of_v<base_class, SpriteType>>>
class Sprite {
public:
SpriteType s;
myclass<Sprite<SpriteType>> t;
Sprite() {
}
auto foo() {
return s;
}
private:
};
That is one of many options.
Another option is to use an interface. i.e. a pure virtual base class that isn't a template.
Example:
I think something like this should do it. Starting to get a hard to follow though.
class base_sprite
{
public:
virtual ~base_sprite(){};
virtual int foo() = 0;
};
template<typename T>
class myclass
{
public:
std::shared_ptr<base_sprite> ptr;
myclass() : ptr(std::make_shared<T>())
{
};
};
template<typename SpriteType>
class Sprite : public base_sprite{
public:
myclass<Sprite<SpriteType>> l;
int foo() override {return 0;};
};
I can already define a function pointer vector with a fixed parameter type in the public: header, then update it in the constructor. But, if I want to be able to pass a function pointer vector with a parameter of any type, how can I define it before the constructor updates it?
#include <iostream>
#include <vector>
class foo {
public:
std::vector<void (*)(int)> functions;
foo(std::vector<void (*)(int)> x) {
functions=x;
}
void run() {
functions[0](2);
}
};
void square(int n) { std::cout << n*n; }
int main() {
foo* bar=new foo(std::vector<void (*)(int)>{square});
bar->run();
return 0;
}
Now, how could I pass a vector to the constructor with any type?
//snippet from above
std::vector<void (*)()> functions; //what do i do here?
template <typename T>
foo(std::vector<void (*)(T)> x) { //this works fine
functions=x;
}
You can turn the class into a class template instead
template<class T>
class foo {
public:
std::vector<void (*)(T)> functions;
foo(std::vector<void (*)(T)> x) : functions(x)
{ }
...
}
foo<int>* bar=new foo(std::vector<void (*)(int)>{square});
I would also recommend switching from a function pointer to std::function and that you don't use raw pointers. Use std::unique_ptr or one of its cousins.
I have the following piece of code. I have abstracted out and my class looks something like this:
#include<iostream>
#include<map>
using namespace std;
template <class K>
class Base {
private:
static std::map<std::string, Base*> derived_map;
//other private data
public:
Base(std::string modName) {
if (derived_map.find(modName) == derived_map.end())
{
derived_map.insert(make_pair(modName, this));
}
}
};
template <class K> std::map<std::string, Base<K>*> Base<K>::derived_map;
class Derived: public Base<Derived>
{
public:
Derived(std::string modname): Base<Derived>(modname)
{
}
};
Derived obj("derived1"); // <<< This casuses segfault
int main()
{
}
When I declare the Derived obj globally, it segfaults. When I declared the Derived obj inside of my main then it doesn't. I am not able to figure out what I might be doing wrong. I am trying to maintain a list of derived class pointers in my base class using a std::map. Any clues ?
You have 2 global variables with dependencies:
obj requires that Base<Derived>::derived_map is initialized correctly.
global initialization across translation unit is done in undefined order.
You may solve your code with something like:
template <class K>
class Base {
private:
static std::map<std::string, Base*>& get_derived_map()
{
static std::map<std::string, Base*> derived_map; // initialized the first time
// get_derived_map is called
return derived_map;
}
//other private data
public:
explicit Base(const std::string& modName) {
get_derived_map().insert(make_pair(modName, this));
}
};
Basically I have a class let's say Parameter that has a get and set variable.
I also have a base class let's say Vehicle that has a method registerParameter(...) that takes a pointer to function member as getter and a pointer to function member as setter. This method is then supposed to write those two pointers into an object of the parameter class and throws this object into a vector.
And last but not least we have a derived class let's say Car and we call registerParameter(...) with the string "color" as parameter name and a getter and setter from this derived class.
Example in code:
Parameter file
#ifndef BASE_H
#define BASE_H
#include "base.h"
class Parameter
{
std::string (Base::*get)();
void (Base::*set)(std::string);
};
#endif
Base file
#ifndef PARAMETER_H
#define PARAMETER_H
#include <vector>
#include "parameter.h"
class Base
{
public:
std::vector<Parameter> list;
void registerNew(std::string (Base::*get)(), void (Base::*set)(std::string))
{
Parameters parameter;
parameter.get = get;
parameter.set = set;
list.push_back(parameter);
}
};
#endif
Derived file
class Derived
{
public:
Derived derived()
{
registerNew(&getColor, &setColor);
}
std::string getColor()
{
return this->color;
}
std::string setColor(std::string newColor)
{
this->color = newColor;
}
private:
std::string color;
};
I've been thinking about this for days now and I really need the solution until friday evening.
You cannot do what are trying:
The types std::string (Base::*)() and std::string (Derived::*)() are very different. std::string (Derived::*)() cannot be auto converted to std::string (Base::*)().
Take the following scenario.
struct Base
{
int foo() { return 10; }
};
struct Derived : Base
{
int bar() { return 20; }
};
int main()
{
Base base;
int (Base::*bf)() = &Base::foo;
(base.*bf)(); // Should be able to call Base:foo(). No problem.
bf = &Derived::bar; // This is a compiler error. However, if this were allowed....
(base.*bf)(); // Call Derived::bar()?? That will be a problem. base is not an
// instance of Derived.
}
Update
You can do something like:
#include <string>
#include <vector>
class Base;
// Create a base class Functor that provides the interface to be used by
// Base.
struct Functor
{
virtual ~Functor() {}
virtual std::string get(Base& base) = 0;
virtual void set(Base& base, std::string) = 0;
};
// Create a class template that implements the Functor interface.
template <typename Derived> struct FunctorTemplate : public Functor
{
// typedefs for get and set functions to be used by this class.
typedef std::string (Derived::*GetFunction)();
typedef void (Derived::*SetFunction)(std::string);
// The constructor that uses the get and set functions of the derived
// class to do itw work.
FunctorTemplate(GetFunction get, SetFunction set) : get_(get), set_(set) {}
virtual ~FunctorTemplate() {}
// Implement the get() function.
virtual std::string get(Base& base)
{
return (reinterpret_cast<Derived&>(base).*get_)();
}
// Implement the set() function.
virtual void set(Base& base, std::string s)
{
(reinterpret_cast<Derived&>(base).*set_)(s);
}
GetFunction get_;
SetFunction set_;
};
class Base
{
public:
std::vector<Functor*> functorList;
void registerFunctor(Functor* functor)
{
functorList.push_back(functor);
}
};
class Derived : public Base
{
public:
Derived()
{
// Register a FunctorTemplate.
registerFunctor(new FunctorTemplate<Derived>(&Derived::getColor,
&Derived::setColor));
}
std::string getColor()
{
return this->color;
}
void setColor(std::string newColor)
{
this->color = newColor;
}
private:
std::string color;
};
Your base class should know the derived class. That sounds complex but the problem has been solved already:
template<typename DERIVED> class Base
{
public:
class Parameter {
std::string (DERIVED::*get)();
void (DERIVED::*set)();
};
private:
std::list<Parameter> list;
// ...
};
class Derived : public Base<Derived> // !!!
{
registerNew(&Derived::getColor, &Derived::setColor);
};
This solution is known as the Curiously Recurring Template Pattern (CRTP).
I'm trying to implement a callback manager that can register and execute the callbacks from different classes, which each classes are from a different DLL.
Each of these classes derives from a common base class. I know how a single class can make use of a template class like below to register and call its own function, but how can this be applied to use on multiple classes sharing the same callback manager?
Any help will be greatly appreciated.
file: callbacktemplate.h
------------------------
#include <functional>
#include <string>
template <class cInstance>
class cCallBackManager
{
private:
typedef void (cInstance::*tFunction)();
typedef std::map<std::string, tFunction> funcMap;
funcMap i_funcMap;
public:
void SetFunPointer(std::string funcName, tFunction function)
{
i_funcMap.insert(std::pair<std::string, tFunction>(funcName, function));
}
void GetFunPointer(cInstance& obj) //how to call this without knowing the type?
{
for (funcMap::iterator it = i_funcMap.begin();it!=i_funcMap.end(); ++it)
{
(obj.*(it->second))();
}
}
};
file:example.h
---------------
#include "callbacktemplate.h"
class A: public base
{
private:
cCallBackManager<A> callback;
public:
A()
{
callback.SetFunPointer<A>("eventA", &A::testcallback);
callback.GetFunPointer(&this); //how to generalize this so this can be called from the callback manager with the class object?
};
~A(){};
void testCallback();
};
class B: public base
{
private:
cCallBackManager<B> callback;
public:
B()
{
callback.SetFunPointer<B>("eventB", &B::testcallback);
};
~B(){};
void testCallback();
};
file: main.cpp
------------------
#include "derived.h"
int main()
{
A a;
B b;
//create a callback manager to execute the callback?
callbackmgr.execute() //execute all the callback
return 0;
}
lf not using templatized callback manager, how can i achieve something like SetFunPointer(EVENT_NAME, (Base Class)A::testCallback)?
Thanks guys. I've managed to come up with something with your "pointers". :)
File: cCallBackInterface.h
template<class cClass>
class cCallBackInterface
{
public:
cCallBackInterface(){};
~cCallBackInterface(){};
typedef void (cClass::*Function)();
cCallBackInterface(cClass* obj, Function _Function)
{
cInstance = obj;
m_Function = _Function;
}
void execute()
{
(cInstance->*m_Function)();
}
private:
cClass* cInstance;
Function m_Function;
};
File: base.h
class BaseModel;
typedef cCallBackInterface<BaseModel> CallBackInterface;
typedef void(BaseModel::*basefn)();
class BaseModel
{
public:
BaseModel(){};
~BaseModel(){};
}
};
class derived : public BaseModel
{
public:
derived(){};
~derived(){};
void dosomething()
{
cout << "derived class is doing something." << endl;
}
};
File: main.cpp
int main()
{
derived a;
std::vector<CallBackInterface> callback;
callback.push_back(CallBackInterface(&a, (basefn)(&derived::Adosomething)));
for(int i = 0; i < callback.size(); i++)
callback[i].execute();
return 0;
}
You can look at this question regarding using member-function pointers.
What it boils down to is that you need the instance as well as the mem-func pointer, you cannot have a generic one to be used anywhere.