Inline means slightly more than "register" to a compiler. (as in the compiler totally ignored the register keyword long before it was deprecated, not in the sense the commands are similar, they are not, were not even)
Back in the day they were like "I will cherish this knowledge from the user", now they are like "Thanks for your input on this matter" then discard it. They are in a MUCH better position than we are to judge.
A lot of work has gone into reducing the penalty of abstraction. This means the compiler can deduce the type of something far better through some quite convoluted statements than previously possible, putting off that v-table jump. If it can work out what's being called it can probably decide if it's worth inlining and stuff like that.
Template used to imply inline, again if you say inline the compiler humours you like a kid doing a card trick (and getting it wrong).
there's no reason you can't inline a virtual in the case of the compiler being able to determine which method you are calling. Much like how it can optimise out variables, it can optimie out function pointers, and virtual basically hides a structure of virtual pointers.
So back in ye-olden days if I do some_derived_instance.some_vritual_method(); there was no reason that couldn't be inlined. Inline never said "IT MUST ININE" it, like register, just gave the compiler a hint.
To answer the question more directly
Your code is NOT CONVOLUTED enough to confuse the compiler. -Winline issues warnings if a function can't be inlined when the compiler ultimately ends up implementing the call.
You will find it difficult to make code convoluted enough in one code file that it cannot tell this. Alias analysis means a union wont hide it. Compilers have a great understanding of code and can "run code" to an extent.
To really test this, put the code for your classes in one file, and use the base clas in another. Then the compiler cannot know what's going on when it compiles the test function, because the call-site is in another object file.
DO NOT USE LINK TIME OPTIMISATION, The compile will still probably inline (with GCC, they just stream the GIMPLE IR, that has all the information attached to it)
Bottom line
It's a bitch to try and fool a modern compiler.
Re: Recursion
The compiler doesn't optimise code, it optimises some intermediate representation. It can "inline recursions" in the sense it represents a recursive function as a wadge of code at a callsite.
It doesn't have a recursion limit it has a limit to the size of the blob it's willing to create. You can make GCC generate HUGE outputs if you "tune" the inliner to be super aggressive. Think Russian dolls, but with N children each.