C++ polymorphism: what am I missing? - c++

I am learning c++ and would like to build something similar to C# events to handle interrupts in an embedded c++ project.
So far I came up with a solution that does almost what I want. However I need some help with polymorphism (?). The following code snippet is kind of a minimum example to reproduce my situation:
#include <iostream>
struct Event
{ };
struct EventHandler
{
virtual void Esr (const Event& I) { }
};
struct EventSender
{
EventSender (EventHandler& Handler) : _Handler (Handler) { }
template <typename T>
void SendEvent (const T&) const
{
_Handler.Esr (T ());
}
EventHandler& _Handler;
};
struct SpecialEvent : public Event
{ };
struct MyHandler : public EventHandler
{
void Esr (const Event& I) override { std::cout << "Event" << std::endl; }
void Esr (const SpecialEvent& I) { std::cout << "SpecialEvent" << std::endl; }
};
int main()
{
MyHandler handler;
EventSender sender (handler);
/* Invoke directly */
handler.Esr (Event ());
handler.Esr (SpecialEvent ());
/* Invoke indirectly */
sender.SendEvent (Event ());
sender.SendEvent (SpecialEvent ()); // Expected cout msg: "SpecialEvent"
return 0;
}
Expected console output:
Event
SpecialEvent
Event
SpecialEvent
Actual console output:
Event
SpecialEvent
Event
Event
What does the compiler/linker here that I am not aware of?

Here you're trying to use overloading, not classic (virtual function based) polymorphism.
What you want (at least as I understand it) is behavior that's essentially the same between using a handler directly, and invoking it indirectly via a sender. The variation that happens is between an Event and a SpecialEvent.
That being the case, classic polymorphism would involve a virtual function in Event that's overridden in SpecialEvent:
struct Event {
virtual void operator()() const { std::cout << "Event\n"; }
};
struct SpecialEvent : public Event {
virtual void operator()() const override { std::cout << "Special Event\n"; }
};
With this in place, a reference (or pointer) to an Event will invoke the member for the actual type. Doing the polymorphism here means we only need one handler class, so the code ends up something like this:
#include <iostream>
struct Event {
virtual void operator()() const { std::cout << "Event\n"; }
};
struct EventHandler {
void Esr(const Event& I) const { I(); }
};
struct EventSender {
template <typename T>
void SendEvent (const T& t) const {
handler.Esr(t);
}
EventHandler handler;
};
struct SpecialEvent : public Event {
virtual void operator()() const override { std::cout << "Special Event\n"; }
};
int main() {
EventHandler handler;
EventSender sender;
/* Invoke directly */
handler.Esr (Event ());
handler.Esr (SpecialEvent ());
/* Invoke indirectly */
sender.SendEvent (Event ());
sender.SendEvent (SpecialEvent ()); // Expected cout msg: "SpecialEvent"
}

You have two methods in MyHandler. One of them overrides the base class method
The other one does not.
One solution would be to declare both methods in the base class:
struct EventHandler
{
virtual void Esr (const Event& I) = 0;
virtual void Esr (const SpecialEvent& I) = 0;
};
That way the compiler can use the type of the argument to resolve the method at the EventHandler level.
If you wanted to avoid the requirement that all derived classes must overload both methods you could do something like this:
struct EventHandler
{
virtual void Esr (const Event& I) = 0;
virtual void Esr (const SpecialEvent& I)
{
// if not overridden, use the non-specialized event handler.
Esr(reinterpret_cast<const Event &>(I));
}
};
To answer your question:
What does the compiler/linker here that I am not aware of?
In C++ a method call is resolved at compile/link time into either 1) a call to a particular block of code (the method body), or 2) an indirect call via a hidden data structure called a vtable. The actual vtable is determined at runtime, but the compiler has to decide which entry in the table to use for the call. (Google vtable for lots more information about what they are and how they are implemented.)
It has to base this resolution on what it's allowed to know. In this case based on the type of the pointer or reference through which the method is called. Note this is NOT necessarily the type of the actual object.
In your case when you call throgh handler the compiler is allowed to know about both methods declared in MyHandler so it can pick the one you expect, but when the call goes through sender, it has to find a method declared in EventSender. There's only one method declared in EventSender. Fortunately the argument can be coerced into a const Event & so the compiler is able to use that method. Thus it uses the vtable entry for that method. So it finds the vtable for MyHandler [at runtime] and uses the vtable entry for
Esr (const Event& I)
and that's how you end up in the wrong method.
BTW: My answer is intended to explain what you are seeing and give you a way to fix your immediate problem. Jerry Coffin's answer gives you an alternative approach that should work better for you in the long term.

First of all, you cannot cast references to a descendant of a base class.
You'll need to use a pointer to that type, and using dynamic_cast.
So, you have
EventSender sender (handler);
in main(). The constructor of sender binds to the base class of MyHandler which is EventHandler, since this is the parameter type in the constructor of MyHandler (= EventHandler::EventHandler). Therefore, EventHandler.Esr(const Event &) is called, which happens to be virtual, so there is a pointer to MyHandler.Esr(const Event &).
Note that technically, Esr(const Event &) and Esr(const SpecialEvent &) are two different methods; they just happen to use the same name.

Related

Polymorphism and function binding

For an event system i'm writing i want to bind callbacks to a list of functions.
Here is a basic example of what i want to do:
#include <iostream>
#include <functional>
#include <string>
class Base {
public:
virtual std::string getType() const = 0;
};
class Derived : public Base {
protected:
int some_data;
public:
Derived(int some_data): some_data(some_data) {}
virtual std::string getType() const {
return "Derived";
}
int getData() const {
return this->some_data;
}
};
class DerivedTwo : public Base {
protected:
double some_data;
public:
DerivedTwo(double some_data): some_data(some_data) {}
virtual std::string getType() const {
return "DerivedTwo";
}
// The type of data is not always the same.
double getData() const {
return this->some_data;
}
};
// The type of member should ALWAYS be Derived but then i can't store it in <callback>
void onDerivedEvent(Base& member) {
std::cout << member.getType() << std::endl;
// This is obviously not possible with member being a base class object
// member.getData();
}
// The type of member should ALWAYS be DerivedTwo but then i can't store it in <callback>
void onDerivedTwoEvent(Base& member) {
std::cout << member.getType() << std::endl;
}
int main() {
std::function<void(Base&)> callback;
callback = std::bind(onDerivedEvent, std::placeholders::_1);
callback(Derived(2));
callback = std::bind(onDerivedTwoEvent, std::placeholders::_1);
callback(DerivedTwo(3.0));
return 0;
}
The only thing i would like to change is that onCallback() should take a derived class member as argument instead of a reference to a base object, so i can call getData() for example.
In this example this would mean:
void onCallback(Derived& derived);
However, if i do this, i can no longer bind() the method to callback because the argument types are not matching.
Does anyone know how to make this work?
// EDIT
Sorry for the confusion here, i updated the source code with some more specifics and examples to maybe clarify what im doing here.
Note:
Since it seems like this is very relevant, here is the specific use case for what i'm trying to do here:
It's part of an event system for an engine i'm building. There are basic events pre-defined but it should be extendable with more specific events by a user using this engine. So there is not definitive list of derived classes. Then some object can subscribe to a specific event type and whenever the central event bus recieves such an event, it calls all subscribed callback functions with the event as argument. The reason i am not adding a one and for all handle function in the derived class is, the events an be used in multiple ways.
Answers to some questions from the comments:
What should happen if you pass onCallback an object that isn't that specific Derived&? (ie, add a Derived2 which has a doStuff2. Pass it to callback. What do you want to happen?
That should not be possible.
I might have not calrified that and also had a misleading information at the beginning which i have editted since then. The type of the passed derived class is always known beforehand. For example: onKeyEvent will always recieve a KeyEvent object and not a base class object or any other derived variants.
However, the variable to which this function is bound should be able to store functions which accept different derived classes from Base
This is my storage for all events:
std::map<EventType, std::list<std::function<void(const Event&)>>> listener_map;
Why isn't onCallback a method in Base that Derived overrides
I answered this in a comment. ...The reason i am not adding a one and for all handle function in the derived class is, the events an be used in multiple ways...
Meaning, i might have an KeyEvent which has the data to a key (which key, is it pressed/released/held) and the listening function(s) can use this data for whatever it wants. (Check if some specific key is pressed, chech if any random key is pressed and so on.) Some other events might not have any data at all and just notify a listener that something happened or have multiple sets of data etc.
Is there, or can there be, a finite, bounded at compile time, central list of all of the types that derive from Base at any point in your code?
In theory yes. During compilation there will be a finite number of Derived classes. However these might be different for the compilation of the library and the compilation of the project using this library.
template<class Base>
struct poly_callback {
template<class T>
static poly_callback make( std::function<void(T&)> f ) {
return { std::function<void(void*)>( [f]( void* ptr ) { f(*static_cast<T*>(static_cast<Base*>(ptr))); }) };
}
template<class T>
poly_callback( void(*pf)(T&) ):poly_callback( make<T>( pf ) ) {}
poly_callback( poly_callback const& ) = default;
poly_callback( poly_callback && ) = default;
void operator()( Base& b ) {
return type_erased( static_cast<void*>(std::addressof(b)) );
}
private:
std::function<void(void*)> type_erased;
poly_callback( std::function<void(void*)> t ):type_erased(std::move(t)) {}
};
A poly_callback<Event> can store a callable with signature compatible to void(Derived&), where Derived is derived from Event. It must be called with exactly an instance of the Derived& type or undefined behavior results as it blindly downcasts.
Stop using std::bind, it is functionally obsolete.
class Base {
public:
virtual std::string getType() const = 0;
};
class Derived : public Base {
protected:
int some_data;
public:
Derived(int some_data): some_data(some_data) {}
virtual std::string getType() const {
return "Derived";
}
int getData() const {
return this->some_data;
}
};
class DerivedTwo : public Base {
protected:
double some_data;
public:
DerivedTwo(double some_data): some_data(some_data) {}
virtual std::string getType() const {
return "DerivedTwo";
}
// The type of data is not always the same.
double getData() const {
return this->some_data;
}
};
// The type of member should ALWAYS be Derived but then i can't store it in <callback>
void onDerivedEvent(Derived& member) {
std::cout << member.getType() << "\n";
std::cout << member.getData() << "\n";
}
// The type of member should ALWAYS be DerivedTwo but then i can't store it in <callback>
void onDerivedTwoEvent(DerivedTwo& member) {
std::cout << member.getType() << "\n";
std::cout << member.getData() << "\n";
}
struct callbacks {
std::unordered_map< std::string, std::vector< poly_callback<Base> > > events;
void invoke( std::string const& name, Base& item ) {
auto it = events.find(name);
if (it == events.end())
return;
for (auto&& f : it->second)
f( item );
}
template<class Derived>
void connect( std::string const& name, void(*pf)(Derived&) )
{
events[name].push_back( pf );
}
template<class Derived>
void connect_T( std::string const& name, std::function<void(Derived&)> f )
{
events[name].push_back( std::move(f) );
}
};
int main() {
callbacks cb;
cb.connect("one", onDerivedEvent );
cb.connect("two", onDerivedTwoEvent );
Derived d(7);
DerivedTwo d2(3.14);
cb.invoke( "one", d );
cb.invoke( "two", d2 );
return 0;
}
Live example.
This can be tweaked for safety and usability. For example, check that the typeid actually matches.
Output is:
Derived
7
DerivedTwo
3.14
and as you can see, the callback functions take Derived& and DerivedTwo& objects.
In my experience this is a bad plan.
Instead, have a broadcaster<KeyboardEvent> keyboard; and don't look up your event registry systems with strings.
A map from string-to-callback only makes sense if there is some way to treat the callbacks uniformly. And you don't want to treat these callbacks uniformly. Even if you chose to store them uniformly for efficiency sake (useful in ridiculously huge frameworks), I'd want type-safe APIs not a map.

Is there a way to reference the class of the current object

I'm making a class which has a method that launches some threads of member functions in the same class. I'm quite new to threads in c++, especially when classes are involved but this is what iv'e come up with.
class A
{
public:
void StartThreads()
{
std::thread fooThread(&A::FooFunc, this);
fooThread.join();
}
protected:
virtual void FooFunc()
{
while (true)
std::cout << "hello\n";
}
};
My question is, if i can get the name of the current object, because now if i create a class B which inherits from A but overwrites FooFunc, FooFunc from class A will be called when i do:
B b;
b.StartThreads();
So i'm looking for a way to replace std::thread fooThread(&A::FooFunc, this) with something like std::thread fooThread(&this->GetClass()::FooFunc, this). I could just make StartThreads virtual and overwrite it in derived classes, but It would be better just to write it once and being done with it. Is there a way to do this or something that results in the same thing?
In case of that your this is known at compile-time then static metaprogramming to the rescue.
C++, Swift and Rust (and now Scala also) are static languages that has a lot of compile time tricks to do for problems like that.
How? In your case templates could help you.
Also, you don't need it to be a member function, it can be a friend function (so that you can easily use templates).
class A
{
public:
template<typename T>
friend void StartThreads(const T& obj);
protected:
virtual void FooFunc()
{
while (true)
std::cout << "hello\n";
}
};
template<typename T>
void StartThreads(const T& obj) {
std::thread fooThread(&T::FooFunc, obj);
fooThread.join();
}
WARNING: This ONLY works if the class is known at compile time, i.e.
class B: public A {
};
...
B b;
A &a = b;
StartThreads(a); // Will call it AS IF IT IS A, NOT B
Another solution:
Functional programming to the rescue, you can use lambdas (or functors using structs if you are on C++ prior to C++11)
C++11:
void StartThreads()
{
std::thread fooThread([=](){ this->FooFunc(); });
fooThread.join();
}
C++98:
// Forward declaration
class A;
// The functor class (the functor is an object that is callable (i.e. has the operator (), which is the call operator overloaded))
struct ThreadContainer {
private:
A &f;
public:
ThreadContainer(A &f): f(f) {}
void operator() ();
};
class A
{
public:
// To allow access of the protected FooFunc function
friend void ThreadContainer::operator() ();
void StartThreads()
{
// Create the functor
ThreadContainer a(*this);
// Start the thread with the "call" operator, the implementation of the constructor tries to "call" the operand, which here is a
std::thread fooThread(a);
fooThread.join();
}
protected:
virtual void FooFunc()
{
while (true)
std::cout << "hello\n";
}
};
class B: public A {
protected:
virtual void FooFunc() {
while(true)
std::cout << "overridden\n";
}
};
void ThreadContainer::operator() () {
f.FooFunc();
}
You've looked at using a virtual FooFunc() directly, and somehow surmised that it doesn't work. (I won't address the accuracy of that here, as that is being brought up in the question's comments.) You don't like the idea of moving the virtual function earlier in the process. So why not move it later? There is a somewhat-common paradigm out there that uses non-virtual wrappers to virtual functions. (Usually the wrapper is public while the virtual function is protected or private.) So, something like:
class A
{
public:
void StartThreads()
{
std::thread fooThread(&A::FooFuncCaller, this); // <-- call the new function
fooThread.join();
}
protected:
void FooFuncCaller() // <-- new function layer
{
FooFunc();
}
virtual void FooFunc()
{
while (true)
std::cout << "hello\n";
}
};
Of course, if the direct call to the virtual Foofunc works, might as well use that. Still, this is simpler than using templates or custom functor classes. A lambda is a reasonable alternative, with the benefit of not changing your class' interface (header file).
Thanks for all of your answers, it turned out that my question was unrelated and that i messed up some other members in the class.
Thanks for your answers giving me some insight into other ways you can do the same thing using different methods. (https://stackoverflow.com/users/9335240/user9335240)

Low latency callback in C++

I have an event driven application. I want to keep the event handler (EventHandler class capable of many/all events) a common implementation - while allowing the EventSource be changeable (specifically - at compile time).
To couple the EventHandler with the EventSource, I will have to store an instance of handler within the EventSource. I tried to store handlers of various forms:
pointer to an interface of EventHandler (that has public handler methods defined in concrete EventHandler's
instance of std::function - this provided greatest flexibility
However, in both cases, the latency in calling the target method/lambda was quite high (on my test setup about 250ns) - and to worse, was inconsistent. May be due to virtual table and/or heap allocation and/or type erasure ???
In order to reduce this latency, I want to make use of templates.
The best I could come up with is:
template <typename EventHandler>
class EventSource1
{
EventHandler* mHandler;
public:
typedef EventHandler EventHandlerType;
void AssignHandler (EventHandler* handler)
{
this->mHandler = handler;
}
void EventuallyDoCallback (int arbArg)
{
this->mHandler->CallbackFunction (arbArg);
}
};
template <EventSourceType>
class EventSourceTraits
{
typedef EventSourceType::EventHandlerType EventHandlerType;
static void AssignHandler (EventSourceType& source, EventHandlerType* handler)
{
source.AssignHandler(handler);
}
};
class EventHandler
{
public:
void CallbackFunction (int arg)
{
std::cout << "My callback called\n";
}
};
int main ()
{
EventSource1<EventHandler> source; /// as one can notice, EventSource's need not to know the event handler objects.
EventHandler handler;
EventSourceTraits<EventSource1>::AssignHandler (source, &handler);
}
This method impose a restriction that all my EventSource's to be a template classes.
Question is: Is this best way to achieve consistent and low latency to callback? Can this code be improved to avoid the event source classes be completely independent of event handler objects' type ?
Is this best way to achieve consistent and low latency to callback?
As suggested in the comments to the question, I'd rather try and measure to know if that's really a problem and what's the best alternative for you.
There doesn't exist the best way, it mostly depends on the actual problem.
can this code be improved to avoid the event source classes be completely independent of event handler objects' type ?
Maybe the following can be a good point from which to start to achieve that:
#include <iostream>
class EventSource1
{
using invoke_t = void(*)(void *C, int value);
template<typename T, void(T::*M)(int)>
static void proto(void *C, int value) {
(static_cast<T*>(C)->*M)(value);
}
invoke_t invoke;
void *handler;
public:
template<typename T, void(T::*M)(int) = &T::CallbackFunction>
void AssignHandler (T* ref)
{
invoke = &proto<T, M>;
handler = ref;
}
void EventuallyDoCallback (int arg)
{
invoke(handler, arg);
}
};
class EventHandler
{
public:
void CallbackFunction (int arg)
{
std::cout << "My callback called: " << arg << std::endl;
}
};
int main ()
{
EventSource1 source;
EventHandler handler;
source.AssignHandler(&handler);
source.EventuallyDoCallback(42);
}
See it on wandbox.

const-correctness in void methods and lambda 'trick'

I have a method that accepts a reference of an object as const, this method doesn't change anything of the method and the const indicates that, the thing is that this method also calls other method that is within the class and is void, doesn't accept any argument and is also virtual, meaning that the class that extends the base class can override the method BUT it needs to be const as well. Eg:
#include <iostream>
class Boz
{
public:
virtual void introduce() const = 0;
};
class Foo
{
public:
virtual void callable() const
{
// ...
}
void caller(const Boz& object) const
{
callable();
object.introduce();
}
};
class Bar : public Boz
{
public:
void introduce() const
{
std::cout << "Hi." << std::endl;
}
};
class Biz : public Foo
{
public:
void callable() const
{
std::cout << "I'm being called before the introduce." << std::endl;
}
};
int main(void)
{
Biz biz;
biz.caller(Bar());
return 0;
}
The output would be:
I'm being called before the introduce.
Hi.
As you can see callable must to be const in order to be called. If I change and do this:
class Biz : public Foo
{
public:
void callable()
{
std::cout << "I'm being called before the introduce." << std::endl;
}
};
It will compile not errors are thrown but the callable method won't be called, but the virtual one as it's defined as const. It's quite obvious.
The trickiest part here:
class Foo
{
public:
virtual void callable()
{
// ...
}
void caller(const Boz& object) const
{
auto trick = [&] () { callable(); };
trick();
object.introduce();
}
};
class Biz : public Foo
{
public:
void callable()
{
std::cout << "I'm being called before the introduce." << std::endl;
}
};
It works and the callable method is called. No errors like passing 'const ...' as 'this' argument.
What I'm trying to do is to call callable without the need of being const and the reason is simple: The method doesn't change anything, he don't have access to the object that is begin passed as argument on caller method then we assume that he doesn't have the need to be const but the compiler throws an error even that way. The real problem is that callable is virtual and classes can extend the base class, implement their own callable and try to call other methods but can't if it's not const as well.
What I want is pretty much that, is to know how can I call the virtual method without the need of being const (the reason is pretty much that, I'm kind forcing the users that extends the class and override the callable method to only call const methods and this is not what I want) and of course understand what happens with the lambda and why it works.
That code with the lambda definitely shouldn't compile, it's simply a GCC bug (reported as PR 60463 and PR 60755) which is now fixed in the svn trunk, by http://gcc.gnu.org/r210292
If you really need to call a non-const member function from a const one you need to cast away the constness:
const_cast<Foo*>(this)->callable();
But this is quite risky, for at least two reasons
if the object was declared const then it is undefined behaviour e.g. const Foo f; f.caller(boz); is undefined behaviour.
you're calling a virtual function, you don't necessarily know that the derived class' override definitely doesn't modify anything. The whole point of virtual functions is that a derived class can do something different and the base class doesn't know the details.
I would change your design so that the virtual function you want to call is const, or the caller function is non-const. Anything else is dangerous.

Issues with C++ template arguments for inheritance

I have a questions about C++ templates. More specifally, by using template arguments for inheritance.
I am facing strange behaviour in a closed-source 3rd party library. There is a C method
factoryReg(const char*, ICallback*)
which allows to register a subclass of ICallback and overwrite the (simplified) methods:
class ICallback
{
public:
virtual void ENTRY(void* data) = 0;
virtual void EXIT(void* data) = 0;
const char* getName() { return _name; } const
ICallback(const char* name) : _name(name) {}
virtual ~ICallback() {}
private:
const char* _name;
};
I have
class BaseCallback : public ICallback
{
public:
BaseCallback(const char* name) : ICallback(name) {}
virtual void ENTRY(void* data) {
std::cout << "in ENTRY base" << std::endl;
}
virtual void EXIT(void* data) {
std::cout << "in EXIT base" << std::endl;
};
class SpecialCallback : public BaseCallback
{
public:
SpecialCallback(const char* name) : BaseCallback(name) {}
virtual void ENTRY(void* data) {
// actually, it's 3rd party code too - assumed to do something like
...
BaseCallback::ENTRY();
}
// no redecl. of EXIT(void* data)
};
template <typename Base>
TemplCallback : public Base
{
public:
TemplCallback(Base& myT) : Base(myT.getName()), _myT(myT)
virtual void ENTRY(void* data) {
std::cout << "in ENTRY templ." << std::endl;
_myT.ENTRY();
}
virtual void EXIT(void* data) {
std::cout << "in EXIT templ." << std::endl;
_myT.EXIT();
}
private:
Base& _myT;
}
Upon registering
SpecialCallback spc("validName");
TemplCallback<SpecialCallback> myCallback(spc);
factoryReg(spc.getName(), &myCallback);
...
// output: "in ENTRY base"
// "in EXIT base"
the callback somehow does not work (debug output not being put out // breakpoints do not apply).
If I omit implementation of the EXIT(void* data) method in my template class TemplCallback - everything works fine!
// output: "in ENTRY templ."
// "in EXIT base"
Is this expected behaviour? I have been told it might be an issue of the MSVC compiler 13.10.6030 I use. Not sure about that.
BTW: The template idea presented here might not be the best choice for whatever I am trying to do ;)
But I am still interested in the matter itself, regardless about design questions.
I suspect that factoryReg doesn't actually invoke the callback, but stores the pointer and invokes the callback when something happens.
If that is the case, then this code:
TemplCallback<SpecialCallback> myCallback(spc);
factoryReg(spc.getName(), &myCallback);
causes factoryReg to store pointer to a temporary, which will go out of scope as soon as your registration function returns. Thus, when the callback is invoked, the object is not alive and you have undefined behaviour.
Your TemplCallback class looks funny. I don't think you actually want it to use a different object, but to invoke the inherited versions of ENTRY and EXIT:
template <class Base>
class TemplCallback : public Base
{
public:
TempCallback(const char* name) : Base(name)
{}
virtual ENTRY(void* data)
{
// do special processing
Base::ENTRY(data);
}
virtual EXIT(void* data)
{
// do special processing
Base::EXIT(data);
}
};
OK, it seems that it is safe to assume that SpecialCallback::ENTRY() calls BaseCallback::EXIT() somehow.
Can't be 100% sure, because it's closed source - but it's quite likely.
So much for "callback" functions...