I expected the compiler to be able to statically resolve a function call to a virtual function if the type of the class is known at compile time (e.g. if the class instance is not being used through a reference or a pointer as illustrated in Case 1) below).
However, I have observed a strange behavior with Visual Studio 2010's C++ compiler and I would like to know if there is any reason for the compiler not to statically bind the calls to the "right" virtual function when the instances of the classes with the virtual functions are members in a structure that is being accessed by reference.
Should I expect the compiler to statically bind the calls to f() in Case 2) below? Is the "reference"ness of cr somehow propagating to cr.a even though a
is an A
and not an A&
?
struct A
{
virtual void f() ;
virtual ~A() ;
};
struct B : A
{
virtual void f() ;
virtual ~B() ;
};
struct C {
A a ;
B b ;
};
C & GetACRef() ;
void test()
{
// Case 1) The following calls to f() are statically bound i.e.
// f() is called without looking up the virtual function ptr.
C c ;
c.a.f() ;
c.b.f() ;
A a ;
a.f() ;
// Case 2) The following calls to f() go through the dynamic dispatching
// virtual function lookup code. You can check if you generate the .asm
// for this file.
C & cr = GetACRef() ; // Note that C is not polymorphic
cr.a.f() ; // visual C++ 2010 generates call to f using virtual dispatching
cr.b.f() ; // visual C++ 2010 generates call to f using virtual dispatching
}
Non- virtual member functions are resolved statically. That is, the member function is selected statically (at compile-time) based on the type of the pointer (or reference) to the object. In contrast, virtual member functions are resolved dynamically (at run-time).
Virtual functions are invoked when you have a pointer or reference to an instance of a class. Static functions aren't tied to the instance of a class but they are tied to the class. C++ doesn't have pointers-to-class, so there is no scenario in which you could invoke a static function virtually.
Using a Virtual Function In C++, late binding is achieved by inserting a virtual keyword preceding the declaration of the function in the base class. This informs the compiler that this function is designated for late binding.
A virtual function cannot be global or static because, by definition, a virtual function is a member function of a base class and relies on a specific object to determine which implementation of the function is called. You can declare a virtual function to be a friend of another class.
Obviously the compiler writers have not bothered to solve this case. Perhaps it is not common enough in real code to be worth their attention.
If GetACRef
is defined elsewhere, it is also possible that C is polymorphic there, which could affect the optimizations.
Note that a compiler isn't solving every possible case where a small test program is "obvious" to a human. The compilers' focus is cases that happen often in large real programs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With