Pure Virtual Functions May Not Have an Inline Definition. Why

Why that pure virtual function cannot be inline?

A virtual function 99% of the time cannot be inlined because the function pointer is resolved at runtime using vtable.

The purpose of a virtual function is to be overloaded by subclasses.
An example :

class A
{
virtual int foo() { return 1; }
}

class B : public A
{
virtual int foo() { return 2; }
}

int main(void)
{
B b;
A *a = &b;

return a->foo();
}

The main function will return 2 and not 1.

If the compiler inline the function it will return 1 because the compiler can only assume that the type of *a is A and not B. So the compiler will not do it if he cannot assume safely the type of *a.

In this example the compiler may successfully and safely assume that virtualization is not needed : This is really depending of the compiler and of optimization level.

In some case the compiler can safely assume that virtualization is not needed and only in these cases the inline keyword makes sense.

Even if you declare a function with the keywords inline, the function may not be inlined.

Anyway adding manually the inline keyword is most of the time not a good idea, compiler today are good and automatically inline function when necessary.
By adding inline you may in some case decrease performance, so it a good practice to not abuse of it

Pure virtual functions may not have an inline definition. Why?

In the SO thread "Why is a pure virtual function initialized by 0?" Jerry Coffin provided this quote from Bjarne Stroustrup’s The Design & Evolution of C++, section §13.2.3, where I've added some emphasis of the part I think is relevant:

The curious =0 syntax was chosen over the obvious alternative of introducing a new keyword pure or abstract because at the time I saw no chance of getting a new keyword accepted. Had I suggested pure, Release 2.0 would have shipped without abstract classes. Given a choice between a nicer syntax and abstract classes, I chose abstract classes. Rather than risking delay and incurring the certain fights over pure, I used the tradition C and C++ convention of using 0 to represent "not there." The =0 syntax fits with my view that a function body is the initializer for a function and also with the (simplistic, but usually adequate) view of the set of virtual functions being implemented as a vector of function pointers. [ … ]

So, when choosing the syntax Bjarne was thinking of a function body as a kind of initializer part of the declarator, and =0 as an alternate form of initializer, one that indicated “no body” (or in his words, “not there”).

It stands to reason that one cannot both indicate “not there” and have a body – in that conceptual picture.

Or, still in that conceptual picture, having two initializers.

Now, that's as far as my telepathic powers, google-foo and soft-reasoning goes. I surmise that nobody's been Interested Enough™ to formulate a proposal to the committee about having this purely syntactical restriction lifted, and following up with all the work that that entails. Thus it's still that way.

Overriding a pure virtual function with inline implementation

The method is already implicitly inline because it appears in the class definition.

inline is not what you think it is. It is not to control whether calls to the function are inlined by the compiler. The compiler will decide this independent of the attribute inline. It merely says: The definition can be in a header, no problem with multiple definitions will arise.

For example you could place all this in a header:

class Derived : public Base
{
void foo();
};

inline Derived::foo() { /* implementation */ }

When the member function definition is in the class body then it is implicitiy inline.

Pure virtual and inline definition

A pure virtual function may have a definition (out of class definition). That is completely optional. But what you are trying to do is plain wrong because

C++03 [Section 10.4/2] says:

[Note: a function declaration cannot provide both a pure-specifier and a definition —end note] [Example:

struct C {
virtual void f() = 0 { }; // Ill-formed
}

However you are free to write

struct device{
virtual void switchon() = 0;
};

void device::switchon() { } // Definition {optional}

int main()
{

}

Why does it make sense to give definition for a pure virtual function?

"we are saying that the function cannot have any definition for the class where this pure virtual function is declared."

That's not what pure virtual means. Pure virtual only means that the containing class cannot be instantiated (is abstract), so it has to be subclassed, and subclasses must override the method. E.g.,

struct A {
virtual ~A() = 0;
};

A::~A() {}

struct B : A {};

int main()
{
A a; // error
B b; // ok
}

Here, the B destructor is implicitly defined. If it was another method that is pure virtual, you'd have to explicitly override it:

struct A {
virtual void foo() = 0;
};

void A::foo() {}

struct B : A {};

int main()
{
B b; // error
}

Providing a definition for a pure virtual method is desirable when the base class must be abstract but still provide some default behavior.

In the specific case of a destructor, it has to be provided because it will be called automatically when subclass instances are destroyed. A program that tries to instantiate a subclass of a class with a pure virtual destructor without a definition will not pass the linker.

Are inline virtual functions really a non-sense?

Virtual functions can be inlined sometimes. An excerpt from the excellent C++ faq:

"The only time an inline virtual call
can be inlined is when the compiler
knows the "exact class" of the object
which is the target of the virtual
function call. This can happen only
when the compiler has an actual object
rather than a pointer or reference to
an object. I.e., either with a local
object, a global/static object, or a
fully contained object inside a
composite."

Pure virtual function not used in one of the derived classes

Clearly compute_altitude is not supposed to be part of your virtual interface since calling it through a base pointer is not guaranteed to do anything reasonable if it is implemented as stub in the derived class.

However, compute_travel_info does seem to be part of the virtual interface that should always be callable through a base pointer.

Therefore compute_travel_info should be (pure) virtual and implemented in all derived classes. Some of these derived classes may have a compute_altitude function that is called and some might not, but that shouldn't matter to the base class. The base class should not have a compute_altitude function at all.

You can provide a default implementation for compute_travel_info in the base class which is only overridden when needed.

You can also call the base class implementation of compute_travel_info in the derived class with a qualified name (e.g. this->travel::compute_travel_info()) if you need to just add some additional work to it.

Or you can move the common behavior into another base class function that is called by the compute_travel_info implementations in the derived classes.



Related Topics



Leave a reply



Submit