#include <iostream>
class A
{
public:
virtual ~A() = default;
virtual void foo(void) = 0;
};
class B : public A
{
private:
int x;
public:
B(int a) : x(a) {}
void foo(void) { std::cout << "B: " << x << "\n"; }
};
class Foo
{
private:
A* a_ptr;
public:
Foo (B& x) { a_ptr = &x; }
A* get_ptr(void) { return a_ptr; }
void dummy(void) { std::cout << "Foo: "; std::cout << a_ptr << "\t "<< typeid(*a_ptr).name() << "\n"; a_ptr->foo(); std::cout << "\n"; }
};
int main(void)
{
B b(10);
Foo f(b);
f.dummy();
return 0;
}
If the constructor of Foo
takes a reference to an object of B
, then this program executes the way I expect it to, i.e. a_ptr->foo()
calls B::foo()
.
However, if the constructor is changed to accept the parameter by value, then a_ptr->foo()
resolves to A::foo()
, and results in a pure virtual method called exception
Sample output (Passed by reference:):
Foo: 0x7fffe90a24e0 1B
B: 10
Sample output (Passed by value):
Foo: 0x7fffc6bbab20 1A
pure virtual method called
terminate called without an active exception
Aborted (core dumped)
I've a vague hunch as to why this might be happening, and I'm looking for some literature or reference which might prove or disprove my hypothesis: When passed by reference, the base class pointer a_ptr
points to an entity whose lifetime exceeds past the call to a_ptr->foo()
.
However, when passed by value, a_ptr
points to a temporary which is lost when the constructor exits.
I suppose this has something to do with the VTABLE
of A
, but I can't quite put my finger on it.
Yes, your suspicion is correct.
When the B
object is passed by value into the Foo
constructor, it becomes a local variable of the constructor. The constructor is saving a pointer to that local object, which goes out of scope when the constructor exits.
So, the call to a_ptr->foo()
in Foo::dummy()
is actually undefined behavior since a_ptr
doesn't even point at a valid object to begin with. But, it doesn't really crash since A::foo()
doesn't use its this
pointer for anything. It just points to a compiler-defined function that throws the pure virtual method called
error, which you don't catch, so your program terminates.