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
Constant Expression Initializer for Static Class Member of Type Double
Random Output Different Between Implementations
Is There Any Reason to Use the 'Auto' Keyword in C++03
Comparing Floating Point Number to Zero
Getting "Source Type Is Not Polymorphic" When Trying to Use Dynamic_Cast
Openmp Set_Num_Threads() Is Not Working
C++ Remove Punctuation from String
How to Set Timeout for Std::Cin
Statically Declared 2-D Array C++ as Data Member of a Class
Super High Performance C/C++ Hash Map (Table, Dictionary)
When Should I Use Typedef in C++
How to Create a Utf-8 String Literal in Visual C++ 2008
Rotate Cv::Mat Using Cv::Warpaffine Offsets Destination Image