Created
August 10, 2015 19:22
-
-
Save marekjm/1900b3dcff9924e81815 to your computer and use it in GitHub Desktop.
An example showing that without guidance (static_cast<>) functional will sometimes not handle inheritance
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Simple test for using std::function with inheritance | |
#include <functional> | |
#include <iostream> | |
class Base | |
{ | |
public: | |
virtual void do_it(const std::string & s) | |
{ | |
std::cout << "Doing " << s << std::endl; | |
} | |
}; | |
class Derived : public Base | |
{ | |
public: | |
void do_it(const std::string & s) override | |
{ | |
for (int i = 0; i < 5; ++i) | |
{ | |
std::cout << i << ": "; | |
Base::do_it(s); | |
} | |
} | |
virtual void dont_do_it(const std::string & s) { | |
std::cout << "Not doing " << s << std::endl; | |
} | |
}; | |
typedef std::function<void(const std::string &)> mfunc; | |
typedef std::function<void(Base*, const std::string &)> bfunc; | |
typedef void (Base::*bmethod)(const std::string &); | |
int main() | |
{ | |
using namespace std::placeholders; | |
Base b; | |
Derived d; | |
mfunc f1 = std::bind(&Base::do_it, b, _1); | |
mfunc f2 = std::bind(&Base::do_it, d, _1); | |
f1("important work..."); | |
f2("important work 5 times"); | |
auto f3 = std::bind(&Base::do_it, b, _1); | |
f3("a bit of time off..."); | |
auto f4 = std::bind(&Derived::dont_do_it, d, _1); | |
f4("important work..."); | |
mfunc f5 = std::bind(&Derived::do_it, d, _1); | |
f5("more important work..."); | |
// now, all is fine and dandy up to this point as we have the objects to bind at our disposal. | |
// however, what if we *don't yet have* the object we will have to call the function on? | |
// we must *store* the member pointer for later use, because we don't have an object we could bind our function to. | |
// no problems with assigning base class member pointer. | |
// everything works as expected. | |
bfunc f6 = &Base::do_it; | |
// works on Base class object... | |
f6(&b, "less important work..."); | |
// ...and with Derived class object | |
f6(&d, "less important work..."); | |
// we can even std::bind stored functions if we want to | |
auto f6b = std::bind(f6, &b, _1); | |
f6b("even less important work..."); | |
auto f6d = std::bind(f6, &d, _1); | |
f6d("even less important work..."); | |
/* | |
we are out of luck if we want to store a pointer to member of derived class in a variable | |
that holds pointers to members of base class, though. | |
and for good reason! | |
imagine the situation when some crazy person would call such a derived-class-only function on a | |
base class pointer... horrible, terrible, awful things would happen (most likely a segfault). | |
uncomment below to see the compiler question your intelligence and programming proficiency (or just | |
remingin you of that not-so-safe thing you'd like to do). | |
*/ | |
//bfunc f7 = &Derived::do_it; | |
// however, it we tell the compiler that: | |
// | |
// 1) we are all consenting adults and we want to engage in the acts of perverse pleasures (i.e. taking pointers to members), | |
// 2) we promise to not use the members irresponsibly (never-ever), | |
// 3) and that we *know* that bad things will happen if we apply the member to an object of a wrong class, | |
// 4) that we still wanna do it, | |
// | |
// it will let us because, heck, if we are too stubborn to be reasoned with then we can go compile ourselves and | |
// the compiler doesn't take responsibility for what will happend (it will only yell at us later "I told you, DIDN'T I?!"). | |
bfunc f7 = static_cast<bmethod>(&Derived::dont_do_it); | |
// but in the end, by the virtue of dynamic dispatch we are still able to call the member, provided we do it on an | |
// object of correct class! | |
// the compiler loves us, so even if it does not approve of our actions it will still help us by generating valid code... | |
// __ __ | |
// / \/ \ | |
// \ / We love you too, compiler! | |
// \ / | |
// \ / for(;;) yours, Programmers <3 | |
// \/ | |
// | |
f7(&d, "any important work... Just chillin' with my buddy, Mr. Compiler :-)"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment