views:

3993

answers:

7

I got this question when I received a code review comment saying virtual functions need not be inline.

I thought inline virtual functions could come in handy in scenarios where functions are called on objects directly. But the counter-argument came to my mind is -- why would one want to define virtual and then use objects to call methods?

Is it best not to use inline virtual functions, since they're almost never expanded anyway?

Code snippet I used for analysis:

class Temp
{
public:

    virtual ~Temp()
    {
    }
    virtual void myVirtualFunction() const
    {
     cout<<"Temp::myVirtualFunction"<<endl;
    }

};

class TempDerived : public Temp
{
public:

    void myVirtualFunction() const
    {
     cout<<"TempDerived::myVirtualFunction"<<endl;
    }

};

int main(void) 
{
    TempDerived aDerivedObj;
    //Compiler thinks it's safe to expand the virtual functions
    aDerivedObj.myVirtualFunction();

    //type of object Temp points to is always known;
    //does compiler still expand virtual functions?
    //I doubt compiler would be this much intelligent!
    Temp* pTemp = &aDerivedObj;
    pTemp->myVirtualFunction();

    return 0;
}
+1  A: 

A compiler can only inline a function when the call can be resolved unambiguously at compile time.

Virtual functions, however are resolved at runtime, and so the compiler cannot inline the call, since at compile type the dynamic type (and therefore the function implementation to be called) cannot be determined.

Visage
When you call a base class method from the same or derived class the call is unambiguous and non-virtual
sharptooth
@sharptooth: but then it would be a non-virtual inline method. The compiler can inline functions you don't ask it to, and it probably knows better when to inline or not. Let it decide.
David Rodríguez - dribeas
@dribeas: Yes, that's exactly what I'm talking about. I only objected to the statement that virtual finctions are resolved at runtime - this is true only when the call is done virtually, not for the exact class.
sharptooth
+1  A: 

inline really doesn't do anything - it's a hint. The compiler might ignore it or it might inline a call event without inline if it sees the implementation and likes this idea. If code clarity is at stake the inline should be removed.

sharptooth
For compilers that operate on single TUs only, they can only inline implicitly functions that they have the definition for. A function can only be defined in multiple TUs if you make it inline. 'inline' is more than a hint and it can have a dramatic performance improvement for a g++/makefile build.
Richard Corden
+1  A: 

With modern compilers, it won't do any harm to inlibe them. Some ancient compiler/linker combos might have created multiple vtables, but I don't believe that is an issue anymore.

anon
+1  A: 

In the cases where the function call is unambiguous and the function a suitable candidate for inlining, the compiler is smart enough to inline the code anyway.

The rest of the time "inline virtual" is a nonsense, and indeed some compilers won't compile that code.

moonshadow
Which version of g++ won't compile inline virtuals?
Thomas L Holaday
Hm. The 4.1.1 I have here now appears to be happy. I first encountered problems with this codebase using a 4.0.x. Guess my info is out of date, edited.
moonshadow
+17  A: 

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."

ya23
True, but it's worth remembering that the compiler is free to ignore the inline specifier even if the call can be resolved at compile time and can be inlined.
sharptooth
Amother situation when I think inlining can happen is when you'd call the method for example as this->Temp::myVirtualFunction() - such invokation skips the virtual table resolution and the function should be inlined without problems - why and if you'd want to do it is another topic :)
RnR
@RnR. It's not necessary to have 'this->', just using the qualified name is enough. And this behaviour takes place for destructors, constructors and in general for assignment operators (see my answer).
Richard Corden
sharptooth - true, but AFAIK this is true of all inline functions, not just virtual inline functions.
Colen
That C++ FAQ thesis is simply a bullshit. Compiler is able to determine the true type (or "exact class") of referenced object. Reference can not be changed during runtime, thus sometimes it is possible to inline virtual method of referenced object.
doc
lz_prgmr
+2  A: 

There is one category of virtual functions where it still makes sense to have them inline. Consider the following case:

class Base {
public:
  inline virtual ~Base () { }
};

class Derived1 : public Base {
  inline virtual ~Derived1 () { } // Implicitly calls Base::~Base ();
};

class Derived2 : public Derived1 {
  inline virtual ~Derived2 () { } // Implicitly calls Derived1::~Derived1 ();
};

void foo (Base * base) {
  delete base;             // Virtual call
}

The call to delete 'base', will perform a virtual call to call correct derived class destructor, this call is not inlined. However because each destructor calls it's parent destructor (which in these cases are empty), the compiler can inline those calls, since they do not call the base class functions virtually.

The same principle exists for base class constructors or for any set of functions where the derived implementation also calls the base classes implementation.

Richard Corden
+1  A: 

I've seen compilers that don't emit any v-table if no non-inline function at all exists (and defined in one implementation file instead of a header then). They would throw errors like missing vtable-for-class-A or something similar, and you would be confused as hell, as i was.

Indeed, that's not conformant with the Standard, but it happens so consider putting at least one virtual function not in the header (if only the virtual destructor), so that the compiler could emit a vtable for the class at that place. I know it happens with some versions of gcc.

As someone mentioned, inline virtual functions can be a benefit sometimes, but of course most often you will use it when you do not know the dynamic type of the object, because that was the whole reason for virtual in the first place.

The compiler however can't completely ignore inline. It has other semantics apart from speeding up a function-call. The implicit inline for in-class definitions is the mechanism which allows you to put the definition into the header: Only inline functions can be defined multiple times throughout the whole program without a violation any rules. In the end, it behaves as you would have defined it only once in the whole program, even though you included the header multiple times into different files linked together.

Johannes Schaub - litb