I have a class which needs more callbacks..
I am trying to implement them with an interface:
class CallbacksInterface
{
public:
virtual bool mycallback1() = 0;
virtual bool mycallback2() = 0;
virtual bool mycallback3() = 0;
};
Class BusImplementation{
public:
addRequest(bool (CallbacksInterface::*callback)());
}
Callback is parameter for addRequest() method and is defined as pointer to interface method.
So I want to add request..
//class with callbacks
class Main:CallbacksInterface{
public:
bool mycallback1(){..};
bool mycallback2(){..};
bool mycallback3(){..};
//..
}
BusImplemantation bus;
Main main;
bus.addRequest(main.mycallback1);
bus.addRequest(main.mycallback2);
bus.addRequest(main.mycallback3);
But I cant pass a callback into my BusImplemantation class
error: argument of type 'bool (Main::)()' does not match 'bool (CallbacksInterface::*)()'
I think there is a solution with templates, but I am programming embedded devices and my compiler is limited.
A simpler approach would be to define a single interface type representing a function:
struct ICallback
{
virtual bool operator()() const = 0;
};
and implement it as many times as necessary:
struct Foo : ICallback
{
virtual bool operator()() const { return true;}
};
struct Bar : ICallback
{
virtual bool operator()() const { return false;}
};
then your bus implementation can take callback interfaces:
class BusImplemantation{
public:
void addRequest(const ICallback* callback) { .... }
};
then
BusImplemantation bus;
Foo foo; // can be called: bool b = foo();
Bar bar; // can be called: bool b = bar();
bus.addRequest(&foo);
bus.addRequest(&bar);
You could also investigate using std::function and avoiding the common interface altogether.
I also strongly suggest going with an abstract interface. However, if you really want the original approach for some reason, you need something like this:
void addRequest(bool (CallbacksInterface::*callback)(), CallbacksInterface* pTarget) {...}
...
bus.addRequest(&CallbacksInterface::mycallback1, &main);
// ! Not &Main::mycallback1 - that wouldn't compile
...
// calling a callback
(pTarget->*callback)();
Related
class A
{
friend void foo();
virtual void print_Var() const{};
};// does not contain variable Var;
template<class T>
class B : public A
{
T Var;
public:
B(T x):Var(x){}
void print_Var() const override
{
std::cout<<Var<<std::endl;
}
};
void foo()
{
std::array<std::unique_ptr<A>, 3> Arr = {
std::make_unique<B<int>>(100),
std::make_unique<B<int>>(20),
std::make_unique<B<std::string>>("Hello Stackoverflow")
};
std::shuffle(Arr.begin(), Arr.end(), std::mt19937(std::random_device()())); // 3rd parameter generated by Clang-Tidy
for (auto &i: Arr)
{
i->print_Var(); // OK
// auto z = i->Var // no member named Var in A
// obviously base class does not contain such variable
// if (i->Var==20) {/* do something*/}
// if (i->Var=="Hello Stackoverflow") {/* do something*/}
}
}
Explanation:
I want to iterate over array of pointers to A, which is filled with pointers to classes derived from A, and depending on what type is variable Var, do some if( ) statement.
Problem is that i cannot access Var, cause its not member of base class. However, it's possible to cout those values by, for example, overloaded function returning void. Could i write function in A class that returns templated type? like:
class A
{
<class T> GetVar()
}
Besides, I feel like I'm dealing with this problem in totally improper way. Can i mix templates and inheritance like that? If not, how should it be designed?
You have a few choices. I'll explain my preferred solution first.
1. Use dynamic dispatch
If you have an array of a base class type, why do you even want to do stuff with Var? That variable is specific to the child class. If you have a A somewhere, you shouldn't even care what B has or hasn't at that place.
Operations on the typed variable should be encapsulated in virtual function in the base class. If you want to do condition and stuff, maybe you could encapsulate that condition into a virtual function that returns a boolean.
2a. Drop the base class and use variant
Sometimes, you know in advance the amount of types that will go into that list. Using a variant and drop the base class is a good solution that may apply to your case.
Let's say you only have int, double and std::string:
using poly = std::variant<B<int>, B<double>, B<std::string>>;
std::array<poly, 3> arr;
arr[0] = B<int>{};
arr[1] = B<double>{};
arr[2] = B<std::string>{};
// arr[2] = B<widget>{}; // error, not in the variant type
std::visit(
[](auto& b) {
using T = std::decay_t<decltype(b)>;
if constexpr (std::is_same_v<B<int>, T>) {
b.Var = 2; // yay!
}
},
arr[0]
);
2b. Drop the base class and use generic functions
Drop the base class entirely, and template your functions that do operation on them. You can move all your function into an interface or many std::function. Operate on that instead of the function directly.
Here's an example of what I meant:
template<typename T>
void useA(T const& a) {
a.Var = 34; // Yay, direct access!
}
struct B {
std::function<void()> useA;
};
void createBWithInt() {
A<int> a;
B b;
b.useA = [a]{
useA(a);
};
};
This is fine for cases where you only have few operations. But it can quickly lead to code bloat if you have a lot of operations or if you have many types of std::function.
3. Use a visitor
You could create a visitor that dispatch to the right type.
This solution would be much close to what you except, but is quite combersome and can break easily when adding cases.
Something like this:
struct B_Details {
protected:
struct Visitor {
virtual accept(int) = 0;
virtual void accept(double) = 0;
virtual void accept(std::string) = 0;
virtual void accept(some_type) = 0;
};
template<typename T>
struct VisitorImpl : T, Visitor {
void accept(int value) override {
T::operator()(value);
}
void accept(double) override {
T::operator()(value);
}
void accept(std::string) override {
T::operator()(value);
}
void accept(some_type) override {
T::operator()(value);
}
};
};
template<typename T>
struct B : private B_Details {
template<typename F>
void visit(F f) {
dispatch_visitor(VisitorImpl<F>{f});
}
private:
virtual void dispatch_visitor(Visitor const&) = 0;
};
// later
B* b = ...;
b->visit([](auto const& Var) {
// Var is the right type here
});
Then of course, you have to implement the dispatch_visitor for each child class.
4. Use std::any
This is litteraly returning the variable with type erasure. You cannot do any operation on it without casting it back:
class A {
std::any GetVar()
};
I personnaly don't like this solution because it can break easily and is not generic at all. I would not even use polymorphism in that case.
I think it will be the easiest way. Just move the comparison method to the interface and override it in derived classes. Add the following lines to yor example:
class A
{
/*..................................................*/
virtual bool comp(const int) const { return false; }
virtual bool comp(const std::string) const { return false; }
virtual bool comp(const double) const { return false; }
};
template<class T>
class B : public A
{
/*..................................................*/
virtual bool comp(const T othr) const override { return othr == Var; }
};
void foo()
{
/*..................................................*/
if (i->comp(20))
{
/* do something*/
}
if (i->comp("Hello Stackoverflow"))
{
/* do something*/
}
/*..................................................*/
}
class A
{
friend void foo();
virtual void print_Var() const{};
};// does not contain variable Var;
template<class T>
class B : public A
{
T Var;
public:
B(T x):Var(x){}
void print_Var() const override
{
std::cout<<Var<<std::endl;
}
};
void foo()
{
std::array<std::unique_ptr<A>, 3> Arr = {
std::make_unique<B<int>>(100),
std::make_unique<B<int>>(20),
std::make_unique<B<std::string>>("Hello Stackoverflow")
};
std::shuffle(Arr.begin(), Arr.end(), std::mt19937(std::random_device()())); // 3rd parameter generated by Clang-Tidy
for (auto &i: Arr)
{
i->print_Var(); // OK
// auto z = i->Var // no member named Var in A
// obviously base class does not contain such variable
// if (i->Var==20) {/* do something*/}
// if (i->Var=="Hello Stackoverflow") {/* do something*/}
}
}
Explanation:
I want to iterate over array of pointers to A, which is filled with pointers to classes derived from A, and depending on what type is variable Var, do some if( ) statement.
Problem is that i cannot access Var, cause its not member of base class. However, it's possible to cout those values by, for example, overloaded function returning void. Could i write function in A class that returns templated type? like:
class A
{
<class T> GetVar()
}
Besides, I feel like I'm dealing with this problem in totally improper way. Can i mix templates and inheritance like that? If not, how should it be designed?
You have a few choices. I'll explain my preferred solution first.
1. Use dynamic dispatch
If you have an array of a base class type, why do you even want to do stuff with Var? That variable is specific to the child class. If you have a A somewhere, you shouldn't even care what B has or hasn't at that place.
Operations on the typed variable should be encapsulated in virtual function in the base class. If you want to do condition and stuff, maybe you could encapsulate that condition into a virtual function that returns a boolean.
2a. Drop the base class and use variant
Sometimes, you know in advance the amount of types that will go into that list. Using a variant and drop the base class is a good solution that may apply to your case.
Let's say you only have int, double and std::string:
using poly = std::variant<B<int>, B<double>, B<std::string>>;
std::array<poly, 3> arr;
arr[0] = B<int>{};
arr[1] = B<double>{};
arr[2] = B<std::string>{};
// arr[2] = B<widget>{}; // error, not in the variant type
std::visit(
[](auto& b) {
using T = std::decay_t<decltype(b)>;
if constexpr (std::is_same_v<B<int>, T>) {
b.Var = 2; // yay!
}
},
arr[0]
);
2b. Drop the base class and use generic functions
Drop the base class entirely, and template your functions that do operation on them. You can move all your function into an interface or many std::function. Operate on that instead of the function directly.
Here's an example of what I meant:
template<typename T>
void useA(T const& a) {
a.Var = 34; // Yay, direct access!
}
struct B {
std::function<void()> useA;
};
void createBWithInt() {
A<int> a;
B b;
b.useA = [a]{
useA(a);
};
};
This is fine for cases where you only have few operations. But it can quickly lead to code bloat if you have a lot of operations or if you have many types of std::function.
3. Use a visitor
You could create a visitor that dispatch to the right type.
This solution would be much close to what you except, but is quite combersome and can break easily when adding cases.
Something like this:
struct B_Details {
protected:
struct Visitor {
virtual accept(int) = 0;
virtual void accept(double) = 0;
virtual void accept(std::string) = 0;
virtual void accept(some_type) = 0;
};
template<typename T>
struct VisitorImpl : T, Visitor {
void accept(int value) override {
T::operator()(value);
}
void accept(double) override {
T::operator()(value);
}
void accept(std::string) override {
T::operator()(value);
}
void accept(some_type) override {
T::operator()(value);
}
};
};
template<typename T>
struct B : private B_Details {
template<typename F>
void visit(F f) {
dispatch_visitor(VisitorImpl<F>{f});
}
private:
virtual void dispatch_visitor(Visitor const&) = 0;
};
// later
B* b = ...;
b->visit([](auto const& Var) {
// Var is the right type here
});
Then of course, you have to implement the dispatch_visitor for each child class.
4. Use std::any
This is litteraly returning the variable with type erasure. You cannot do any operation on it without casting it back:
class A {
std::any GetVar()
};
I personnaly don't like this solution because it can break easily and is not generic at all. I would not even use polymorphism in that case.
I think it will be the easiest way. Just move the comparison method to the interface and override it in derived classes. Add the following lines to yor example:
class A
{
/*..................................................*/
virtual bool comp(const int) const { return false; }
virtual bool comp(const std::string) const { return false; }
virtual bool comp(const double) const { return false; }
};
template<class T>
class B : public A
{
/*..................................................*/
virtual bool comp(const T othr) const override { return othr == Var; }
};
void foo()
{
/*..................................................*/
if (i->comp(20))
{
/* do something*/
}
if (i->comp("Hello Stackoverflow"))
{
/* do something*/
}
/*..................................................*/
}
Please consider the following (simplified) class hierarchy and processing functions:
struct msgBase
{
virtual int msgType() const=0;
};
struct msgType1:public msgBase
{
virtual int msgType() const{return 1;}
};
struct msgType2:public msgBase
{
virtual int msgType() const {return 2;}
};
void process(const msgType1& mt1)
{
// processing for message type 1
}
void process(const msgType2& mt2)
{
// processing for message type 2
}
void process(const msgBase& mbase)
{
switch(mbase.msgType())
{
case 1:
process(static_cast<const msgType1&>(mbase));
break;
case 2:
process(static_cast<const msgType2&>(mbase));
break;
}
}
In an integrated design, msgBase would be given a virtual "process" method, to avoid needing to iterate over the types.
If it's not possible or desirable to modify any of the classes, are there any alternatives to iterating over the types?
I've experimented with a decorator/factory pattern where a parallel hierarchy of classes encapsulates the given classes, and implements the necessary virtual functions, but this results in an awful lot of boilerplate, and the factory function still needs to iterate over the types!
I could replace the switch statement with a series of dyamic_casts, but that still leaves the same weaknesses.
As requested by Simon, here is what I mean by CRTP:
typedef <class Derived>
struct msgBase
{
virtual void process(){
// redirect the call to the derived class's process()
static_cast<Derived*>(this) -> process();
};
struct msgType1:public msgBase<msgType1>
{
void process(){
// process as per type-1
}
};
struct msgType2:public msgBase<msgType1>
{
void process(){
// process as per type-2
}
};
What's happening here? Consider this case:
msgBase* msg = new msgType1();
msg->process();
normally (without CRTP) this would only call msgBase::process(). But now, msgBase "knows" about msgType1 using the template, so it is redirected to msgType1::process at compile time.
Something like this could work:
These classes are used to do the casting automatically:
struct dispatcher_base {
virtual void process(const msgBase&) = 0;
};
template <class T>
struct dispatcher_impl : dispatcher_base {
void process(const msgBase& b) override {
::process(static_cast<const T&>(b));
}
};
We'll store them in a map:
auto g_table = std::map<int, std::unique_ptr<dispatcher_base>>{};
But now you have to initialize this table somewhere:
template <class T>
void register_msg() {
g_table[T{}.msgType()].reset(new dispatcher_impl<T>{});
}
...
register_msg<msgType1>();
register_msg<msgType2>();
You can add an assert to register_msg to make sure that msgTypes are unique.
Your process function will look like this:
void process(const msgBase& b) {
assert(g_table.find(b.msgType()) != g_table.end());
g_table[b.msgType()]->process(b);
}
You can replace assert with any other logic of course.
If you can't modify the classes then you can use decorators to get polymorphic type deduction.
struct DecorBase {
DecorBase(msgBase& b) : b_(b) {}
virtual ~DecorBase() {}
virtual void process() = 0;
msgBase& b_;
};
struct DecorType1 : public DecorBase {
DecorType1(msgType1& t1) : DecorBase(t1) {}
void process() override {
std::cout << "Processing Type 1" << std::endl;
}
};
struct DecorType2 : public DecorBase {
DecorType2(msgType2& t2) : DecorBase(t2) {}
void process() override {
std::cout << "Processing Type 2" << std::endl;
}
};
And use it like this:
msgType1 t1;
msgType2 t2;
DecorType1 dt1(t1); // Wrap objects in respective decorator.
DecorType2 dt2(t2);
DecorBase& base = dt2;
base.process(); // Uses polymorphism to call function in derived type.
This will require you to write a decorator for every derived type but at least you don't have to iterate over all types during the function call.
I've implemented my callbacks with interface..
struct ICallback
{
virtual bool operator()() const = 0;
};
and function for adding a callback
void addCallback(const ICallback* callback) { .... }
and use, callback is in some class
class BusImplemantation{
public:
struct Foo : ICallback
{
virtual bool operator()() const { return true;}
}foo;
void OtherMethod();
int OtherMember;
};
But because callback is class(not function/method), I cant within callback access to OtherMethod and OtherMember. If callback would be not class, but only method than it would be possible.(inner class vs. method)
I cant pass OtherMethod and OtherMember to callback as parameters.
Is there any better solution for that? maybe with templates?
Use std::function:
void addCallback(const std::function<bool()>) { .... }
class BusImplemantation{
public:
bool Callback() { return true; }
void OtherMethod();
int OtherMember;
};
BusImplemantation obj;
addCallback(std::bind(&BusImplemantation::Callback, obj));
Check out boost::bind for a bunch of alternatives on how to implement this.
Could you do something like this instead:
typedef std::function<bool()> CallbackFunc;
void addCallback(const CallbackFunc callback) { .... }
class BusImplemantation{
public:
struct Foo
{
Foo(member) : OtherMember(member) { }
bool operator()() const { return true; }
void OtherMethod();
int OtherMember;
}foo;
};
Instead of making your callback an interface, make it use std::function to make it a function object (a Functor), and any extra data or methods that your functor needs can be a part of the functor class.
The whole point of using callback objects instead of free functions is that you can associate arbitrary state with them:
class BusImplemantation{
public:
struct Foo : ICallback
{
explicit Foo(BusImplementation &p) : parent(p) {}
virtual bool operator()() const;
private:
BusImplementation &parent;
} foo;
BusImplementation() : foo(*this)
{
addCallback(&foo)
}
void OtherMethod();
int OtherMember;
};
bool BusImplementation::Foo::operator() () const
{
if (parent.OtherMember == 0) {
parent.OtherMethod();
return false;
}
return true;
}
I think your ICallback interface must have pointer to controlled class with base interface, assume it BusImplemantation and inside callback use this pointer.
struct ICallback
{
virtual bool operator()() const = 0;
void setControlObject(BusImplemantation* o)
{
obj = o;
}
BusImplemantation* obj;
};
class BusImplemantation
{
public:
void addCallback(const ICallback* callback)
{
callback->setControlObject(this);
}
void OtherMethod();
int OtherMember;
};
And use:
class SomeCb : ICallback
{
bool operator()
{
obj->OtherMethod();
return true;
}
}
I'm working on a plugin framework, which supports multiple variants of a base plugin class CPlugin : IPlugin. I am using a boost::shared_ptr<IPlugin> for all reference to the plugins, except when a subsystem needs the plugin type's specific interface. I also need the ability to clone a plugin into another seprate object. This must return a PluginPtr. This is why CPlugin is a template rather than a straight class. CPlugin::Clone() is where the template paramter is used. The following are the class definitions I am using:
IPlugin.h
#include "PluginMgr.h"
class IPlugin;
typedef boost::shared_ptr<IPlugin> PluginPtr;
class IPlugin
{
public:
virtual PluginPtr Clone() =0;
virtual TYPE Type() const =0;
virtual CStdString Uuid() const =0;
virtual CStdString Parent() const =0;
virtual CStdString Name() const =0;
virtual bool Disabled() const =0;
private:
friend class CPluginMgr;
virtual void Enable() =0;
virtual void Disable() =0;
};
CPlugin.h
#include "IPlugin.h"
template<typename Derived>
class CPlugin : public IPlugin
{
public:
CPlugin(const PluginProps &props);
CPlugin(const CPlugin&);
virtual ~CPlugin();
PluginPtr Clone();
TYPE Type() const { return m_type; }
CStdString Uuid() const { return m_uuid; }
CStdString Parent() const { return m_guid_parent; }
CStdString Name() const { return m_strName; }
bool Disabled() const { return m_disabled; }
private:
void Enable() { m_disabled = false; }
void Disable() { m_disabled = true; }
TYPE m_type;
CStdString m_uuid;
CStdString m_uuid_parent;
bool m_disabled;
};
template<typename Derived>
PluginPtr CPlugin<Derived>::Clone()
{
PluginPtr plugin(new Derived(dynamic_cast<Derived&>(*this)));
return plugin;
}
An example concrete class CAudioDSP.h
#include "Plugin.h"
class CAudioDSP : CPlugin<CAudioDSP>
{
CAudioDSP(const PluginProps &props);
bool DoSomethingTypeSpecific();
<..snip..>
};
My problem (finally) is that CPluginMgr needs to update m_disabled of the concrete class, however as it is passed a PluginPtr it has no way to determine the type and behave differently according to the template paramater. I can't see how to avoid declaring ::Enable() and ::Disable() as private members of IPlugin instead but this instantly means that every section of the application now needs to know about the CPluginMgr class, as it is declared as a friend in the header. Circular dependancy hell ensues. I see another option, declare the Enable/Disable functions as private members of CPlugin and use boost::dynamic_pointer_cast<CVariantName> instead.
void CPluginMgr::EnablePlugin(PluginPtr plugin)
{
if(plugin->Type == PLUGIN_DSPAUDIO)
{
boost::shared_ptr<CAudioDSP> dsp = boost::dynamic_pointer_cast<CAudioDSP>(plugin);
dsp->Enable();
}
}
This however leads to lots of duplicate code with many multiple variants of the base CPlugin template. If anyone has a better suggestion please share it!
You can easily write :
class CPluginMgr;
class IPlugIn ..
{
friend CPluginMgr;
...
};
Only a predefinition is needed for friend.
I think your get in trouble trying to return a shared_ptr in clone method. Why don't you make use of covariant return types? What you are doing is a common idiom called Virtual Constructor.
class IPlugin
{
public:
virtual IPlugin* clone() = 0;
// ...
}
class CPluginMgr;
class CPlugin : public IPlugin
{
public:
virtual CPlugin* clone() = 0;
friend CPluginMgr; // as #Christopher pointed out
void Enable(bool enable) { m_disabled = !enable; }
// ...
}
class CAudioDSP : public CPlugin
{
public:
virtual CAudioDSP* clone();
// ...
}
CAudioDSP* CAudioDSP::clone()
{
return new CAudioDSP(*this); // assume copy constructors are properly implemented
}
Returning a shared_ptr may lead you to make errors (as early destruction of temparary objects) and I think is not usually a good idea.