The solution is rather simple: do not pass objects by value!
There are two reasons why we pass by value, we can tackle each case separately.
In our example, m1 is not a const method. This means the method can potentially change the object that provides the context. Passing a parameter by value protects the original object because only a copy is given to the subroutine.
If this is, in fact, what is required, then we can change f1 as follows:
This code solves the problem because when an object is passed by reference, the virtual methods continue to stick with the object. However, it is the responsibility of the caller to clone the object because the called subroutine has no access to the subclass (B in our case).
If method m1 is not changing the object that provides the context, and f1 does not intend to change p1, then the solution is easy. First make m1 a const method in both class A and class B. Next, change subroutine f1 as follows:
This fixes the problem because p1 is now passed by reference, so the virtual method stays with the object. At the same time, we are also informing the compiler to make sure the body of f1 do not make any changes to the object aliased by p1.