Reputation: 30615
Can someone explain the below paragraph please, no explanation is given:
The reason it works is that, in virtually all implementations of C++, virtual functions are implemented with a "virtual function table", which is an array of pointers to functions. This is incompatible with function inlining because you simply can't have a pointer to inline code. Thus for most situations, virtual and inline are incompatible; the compiler will simply ignore the inline statement. However, there is one situation whereby they are compatible: where the object is accessed directly instead of through a pointer.
"High Performance Game Programming in C++", Paul Pedriana
Can someone please explain why the two sentences in bold are so?
Upvotes: 3
Views: 231
Reputation: 137800
First, the keywords aren't incompatible in any way. The paragraph is discussing the underlying implementation. A particular function call may be either inlined or go through a virtual dispatch, but usually not both. To understand why, you just need to understand what an inline call or a virtual call is.
An inlined function call is one where at least part of the called function is spliced directly into the calling function. This is a low-level optimization that the compiler may perform even on functions that aren't defined as inline
. But in the early days when compilers were dumber and executable code size was more important, the keyword was more directly related to the optimization feature.
A virtual call is one where the caller doesn't know exactly what function will be executed. The function's implementation needs to be looked up (dispatched) according to the class at runtime.
So if the function will only be determined at runtime, the compiler cannot splice two functions together. It doesn't know what function would get spliced in.
But you can call a virtual
function without making a special dispatch. This occurs if the compiler can be sure of the object's actual type at compile time. For example, if dog
is derived from pet
with a virtual
method speak
,
dog fido;
fido.speak(); // direct dispatch: we know fido is a dog.
But this is not the case if we have a reference:
bird buddy;
pet &favorite = prefer_dogs? fido : buddy;
favorite.speak(); // favorite may be a bird or dog: need virtual dispatch
Most of the time, when you call a virtual
function you do so through a virtual dispatch.
There is another case, which as far as I know is only theoretical: if the compiler can be sure of the whole class hierarchy (or the choices in a given instance), it could add a Boolean test whether favorite
is a bird
or a dog
and inline both function calls as alternatives in an automatically-generated if … else
statement. But anyway, this is just nuts and bolts that you shouldn't worry about.
What's important is that a virtual
function is called according to the type the object was defined as, and an inline
function may be defined in a header file. And that's all that matters.
Upvotes: 4
Reputation: 17163
It is not "incompatible", just when actually virtual call is placed it is impossible to inline the unknown code. When static call is made to the function inlining will work alright.
The text is not very well formed, but if you already know what it wants to tell, you can find it there. ;-)
Upvotes: 0
Reputation: 258588
It simply means the compiler won't inline a call it has to resolve at run-time.
Suppose you have
struct A
{
virtual void foo() {};
};
and
void test(A* a)
{
a->foo();
}
This call is resolved at runtime. Since foo()
could have been overriden by a deriving class and a
could point to an object of a derived type, a->foo()
can't be inlined - it will be resolved by a lookup.
The second statement means that virtual
functions could be inlined in some situations:
void test(A a)
{
a.foo();
}
In this case, a
is of type A
(even if the original object passed to the function was a derived type, it was sliced because you passed by value) - the call is guaranteed to call A::foo
so it can be inlined by the compiler.
Upvotes: 5