I read sometime back (probably on c.l.c++.moderated) that virtual function calls can be templatized. I tried something on the following lines.
#include <iostream>
template<class T, class FUN>
void callVirtual(T& t, FUN f){
(*t.*f)();
}
struct Base{
virtual ~Base(){}
virtual void sayHi()=0;
};
struct Derived : public Base{
void sayHi(){
std::cout << "Hi!" << std::endl;
}
};
void Test(){
Base* ptr = new Derived;
callVirtual(ptr,&Base::sayHi);
}
int main()
{
Test();
return 0;
}
Output:
Hi!
The templatized method though given the address of pure virtual base member method at compile time calls the correct method at runtime. Is it legal in standard C++ to take address of a pure virtual member?
Thanks in advance
EDIT-1: I removed the second part of the question 'how does it work?'. Looks like that is what is catching attention.
EDIT-2: I searched c.l.c++.moderated and came across this link (http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/5ddde8cf1ae59a0d). The consensus seems like since the standard does not restrict it, it is vaild.
EDIT-3: After reading the codeproject article (thanks to ovanes), i am thinking that the compilers do some magic. Since virtual functions are implemented via vtable (which is compiler specific), taking address of a virtual function always gives the offset in the vtable. Depending on the 'this' pointer used, the appropriate function (whose address is at the offset) is called. I am not sure how to vindicate this though as the standard does not say anything abt it!
You may call a virtual function as long as it is not a pure virtual function, and as long as you know that what you are calling is the method from the class itself and not expecting any polymorphism. Calling a pure virtual function from a constructor is undefined behaviour even if it has an implementation.
A pure virtual function is a function that must be overridden in a derived class and need not be defined. A virtual function is declared to be “pure” using the curious =0 syntax. For example: class Base {
A virtual function is a member function of base class which can be redefined by derived class. A pure virtual function is a member function of base class whose only declaration is provided in base class and should be defined in derived class otherwise derived class also becomes abstract.
You can call a virtual function in a constructor, but be careful. It may not do what you expect. In a constructor, the virtual call mechanism is disabled because overriding from derived classes hasn't yet happened. Objects are constructed from the base up, “base before derived”.
Sure it is. Your code is no different than merely calling the pure virtual method like this:
void Test()
{
Base* ptr = new Derived;
ptr->sayHi();
delete ptr;
}
The only difference is that you have another mechanism for doing the call, and in this case through callVirtual().
As Magnus Skog said, the template part isn't really relevant. What it boils down to is that:
(ptr->* &Base::sayHi)()
seems to work, but
ptr->Base::sayHi()
obviously doesn't because sayHi is pure virtual.
I haven't been able to find anything in the standard about what happens when you take the address of a virtual, or pure virtual, function though. I'm not sure it's legal. It works in GCC and MSVC though, and Comeau's online compiler doesn't complain either.
Edit
Even if it is valid, as your edits say, I'm still wondering what it means.
If we assume for simplicity that sayHi
is non-pure (so a definition of Base::sayHi
exists), then what happens if I take the address of it? Do I get the address of Base::sayHi, or the address of the function that the vtable points to (Derived::sayHi in this case)?
Apparently, compilers assume the latter, but why?
Calling ptr->Base::sayHi()
calls sayHi
in the base class, but taking the address of Base::sayHi
gives me the address of Derived::sayHi
It seems inconsistent to me. Is there some rationale behind this that I'm missing?
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