Sign in to follow this  
Ashkan

Will this syntax avoid virtual calls?

Recommended Posts

Just a quick question. Will the following syntax avoid the virtual call?
class Base {
public:
   virtual void F() { // do something here }
};

class Derived : public Base {
public:
   virtual void F() { // do something here }

   void g() {
       // is compiler smart enough to understand that I don't need runtime polymorphism here?
       this->Derived::F();
   }
}

Thanks /EDIT: Sorry I posted in the wrong forum

Share this post


Link to post
Share on other sites
When in doubt about code generation, ask your compiler. Most compilers come with an option to compile to assembly. For example, with MSVC you can use the /FAs switch and with gcc you can use the -S switch.

Share this post


Link to post
Share on other sites
Yes, it will avoid the use of the vtable.

When you're unsure, another option (for testing only) is to intentionally corrupt the vptr. If the call still works, then you know it's not using the vtable.

Here's one article on the topic: Smashing C++ Vptrs

Basically, in MSVC, the Vptr will be at the beginning of the class. With GCC, it's at the end. So, if you know there's a Vptr, you can intentionally write over the vptr with say, NULL. Then make your call and see what happens.

Techniques like this, while they should never be used in production code, are kind of cool for learning more about some of the deep internals of C++.

Share this post


Link to post
Share on other sites
With the Derived:: specifier, the call is statically bound (that is, the compiler must call the version of the function that is present in the Derived class) and as such it is neither useful nor possible to use a virtual table to resolve the call.

Without it, the call is dynamically bound in order to allow calling of a function defined in a class which inherits from Derived, and will use the compiler's implementation of dynamic binding (usually, virtual functions).

Share this post


Link to post
Share on other sites
Here's the generated assembly:


; 261 : // is compiler smart enough to understand that I don't need runtime polymorphism here?
; 262 : this->Derived::F();

00023 8b 4d f8 mov ecx, DWORD PTR _this$[ebp]
00026 e8 00 00 00 00 call ?F@Derived@@UAEXXZ ; Derived::F


As far as I can tell, the call has avoided vftable. BTW, what a kinky idea smashing vptr is!

Thanks everybody

Share this post


Link to post
Share on other sites
Whether or not this is a sensible thing to do depends on what exactly a class inheriting from Derived and implementing a new version of F() should expect from a call to g(), should it expect the call to behave as before or should it expect the call to behave differently because of the new implementation of F()?

Share this post


Link to post
Share on other sites
I mostly use this method for code reuse. For the sake of discussion, let's say F() is a function that computes the size of a container via some non-trivial computations. g() on the other hand is a function that requires the size of this container to iterate over it. Besides, we definitely don't need runtime polymorphism here since we exactly know what implementation of the interface we need: the one that we are currently implementing. Therefore the best choice in my opinion is to use F() AND avoid the costs of a virtual call at the same time, which this syntax does. A more verbose approach is to factor the common code in another function and use that in both F() and g().

Share this post


Link to post
Share on other sites
Quote:
Original post by Ashkan
I mostly use this method for code reuse. For the sake of discussion, let's say F() is a function that computes the size of a container via some non-trivial computations. g() on the other hand is a function that requires the size of this container to iterate over it. Besides, we definitely don't need runtime polymorphism here since we exactly know what implementation of the interface we need: the one that we are currently implementing. Therefore the best choice in my opinion is to use F() AND avoid the costs of a virtual call at the same time, which this syntax does. A more verbose approach is to factor the common code in another function and use that in both F() and g().


The only question with this is whether or not this is the appropriate behavior in all cases. Can someone inherit from Derived? If so, then it could be logically appropriate that the second Derived class (DerivedDerived?) would have the desired implementation of F.

Share this post


Link to post
Share on other sites
Quote:
Original post by Ashkan
Besides, we definitely don't need runtime polymorphism here since we exactly know what implementation of the interface we need: the one that we are currently implementing.


No, you don't. You know that the implementation you need inherits from the one you are currently implementing.

As it stands, someone could inherit from Derived and change the behavior of the F function. For instance, using a multimap-like container to implement a map-like container where binding a key to a new value hides the old binding of that key until the new binding is removed—the old bindings are still being stored, but they do not count against the container's size nor do they appear in iterations.

If your function g assumes that Derived::F computes the number of elements in the container, then this assumption will be wrong and you will get strange behavior as a result.

Share this post


Link to post
Share on other sites
Quote:
Original post by Ashkan
Besides, we definitely don't need runtime polymorphism here since we exactly know what implementation of the interface we need: the one that we are currently implementing. Therefore the best choice in my opinion is to use F() AND avoid the costs of a virtual call at the same time, which this syntax does.

By doing this you're implicitly making it dangerous to inherit from Derived.

I say implicitly because there is nothing outwardly obvious from the class' interface to indicate that inheritance is dangerous (like a non-virtual destructor for example); in-fact the interface, being mostly virtual, makes it both reasonable and indeed inviting to believe that inheriting from Derived is safe and expected.

Quote:
A more verbose approach is to factor the common code in another function and use that in both F() and g().

This new function should probably be virtual for the same reason that F() is virtual now.

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
Quote:
Original post by Ashkan
Besides, we definitely don't need runtime polymorphism here since we exactly know what implementation of the interface we need: the one that we are currently implementing.


No, you don't. You know that the implementation you need inherits from the one you are currently implementing.

As it stands, someone could inherit from Derived and change the behavior of the F function. For instance, using a multimap-like container to implement a map-like container where binding a key to a new value hides the old binding of that key until the new binding is removed—the old bindings are still being stored, but they do not count against the container's size nor do they appear in iterations.

If your function g assumes that Derived::F computes the number of elements in the container, then this assumption will be wrong and you will get strange behavior as a result.


Yes, I now see the point you guys are making, which makes me wonder what the correct solution is. Should I factor the common code into a third function which is used by both F() and g()?

Quote:

Quote:
Original post by Ashkan
A more verbose approach is to factor the common code in another function and use that in both F() and g().


This new function should probably be virtual for the same reason that F() is virtual now.


But this design is also prone to the same set of problems. What if this third virtual function is overridden in classes Derived from this class?!

Share this post


Link to post
Share on other sites
Show real code for a real example of what you're doing. Otherwise there's no point in giving design advice for what to do.

Share this post


Link to post
Share on other sites
Quote:
Original post by Ashkan
Yes, I now see the point you guys are making, which makes me wonder what the correct solution is. Should I factor the common code into a third function which is used by both F() and g()?

If there is common code then refactoring is, typically, a good idea anyway.

As for a correct solution, it sounds like you want runtime polymorphism but without the overhead, which just isn't do-able. The solution would be to call the virtual function normally, with vtable lookup and everything.

Quote:

Quote:

This new function should probably be virtual for the same reason that F() is virtual now.


But this design is also prone to the same set of problems. What if this third virtual function is overridden in classes Derived from this class?!

Oh, I didn't mean for you to statically call this function as you're right it would suffer the same problems if this was the case. I was expecting you to make a runtime polymorphic call to it. [smile]

If you can provide more context to your actual problem then there might be a statically bound solution, although I presume based on your previous posts that you've ruled out a totally-at-compile-time static polymorphic approach?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this