Case where the problem occours
Please consider the following c++ code:
#include <functional>
#include <iostream>
#include <string>
// Superclass
class A {
public:
virtual std::string get() const {
return "A";
}
};
// Subclass
class B : public A {
public:
virtual std::string get() const {
return "B";
}
};
// Simple function that prints the object type
void print(const A &instance) {
std::cout << "It's " << instance.get() << std::endl;
}
// Class that holds a reference to an instance of A
class State {
A &instance;
public:
State(A &instance) : instance(instance) { }
void run() {
// Invokes print on the instance directly
print(instance);
// Creates a new function by binding the instance
// to the first parameter of the print function,
// then calls the function.
auto func = std::bind(&print, instance);
func();
}
};
int main() {
B instance;
State state(instance);
state.run();
}
In this example, we have two classes A
and B
. B
inherits from class A
. Both classes implement a simple virtual method that returns the type name.
There is also a simple method, print
, that accepts a reference to an instance of A
and prints the type.
The class State
holds a reference to an instance of A
. The class also has a simple method that calls print
by two different means.
Where it gets odd
The sole method in state first calls print
directly. Since we supply an instance of B
int the main method, the output is It's B
, as expected.
For the second call, however, we bind the instance to the first parameter of print
using std::bind
. Then we call the resulting function without any arguments.
In this case, however, the output is It's A
. I would have expected the output It's B
, as before, since it is still the same instance.
If I declare the parameters as pointers instead of references, std::bind
works as expected. I also placed some logging into the constructors of both classes to verify that no instances are created accidentally.
Why does this happen? Does std::bind
discard some type information in this case? To my understanding, this must not happen since the method invocation should be managed by a vtable lookup via runtime.