问题
Let's see this code:
class CBase
{
public:
virtual vfunc() { cout << "CBase::vfunc()" << endl; }
};
class CChild: public CBase
{
public:
vfunc() { cout << "CChild::vfunc()" << endl; }
};
int main()
{
CBase *pBase = new CBase;
((CChild*)pBase)->vfunc(); // !!! important
delete pBase;
return 0;
}
The output is:
CBase::vfunc()
But I want to see: CChild::vfunc()
Explicit ((CChild*)pBase) casts to type "CChild*". So why to call derived vfunc() I need replace "important" string with: ((CChild*)pBase)->CChild::vfunc();
回答1:
That's not how it works - this is:
CBase *pBase = new CChild;
pBase->vfunc();
virtual
function calls are resolved dynamically on pointers & references (unless you call the method explicitly, like you did). Which means it doesn't matter what you tell the compiler the pointer is, it will look for the method in the vftable. Which, in your case, is the vftable
of CBase
.
回答2:
You can't. *pBase
is an object of type CBase
. You cannot treat it as if it were a CChild
because it isn't a CChild
object.
Use of the pointer obtained by the cast to CChild*
causes your program to exhibit undefined behavior.
回答3:
the other answers make important points -- to supplement: if you may in fact be dealing with a CChild
(e.g. it is a reference passed as a parameter), then you can use dynamic_cast
to downcast. however, high reliance on dynamic_cast
is often an indication your design has gone wrong.
detail on the cast can be found here: http://msdn.microsoft.com/en-us/library/cby9kycs(v=vs.80).aspx
so the process would entail casting the CBase
parameter to CChild
via dynamic_cast
, if the reference is a CChild
and dynamic_cast
succeeds, then you could be sure you are dealing with a CChild
and you could then safely use it as a CChild
.
回答4:
The problem here seems very simple. CBase can not magically upgrade to CChild! Let me rewrite your example and add some comments. It should be self explanatory...
#include <iostream>
class CBase {
public:
virtual void vfunc() { std::cout << "CBase::vfunc()" << std::endl; }
virtual ~CBase(){} // Virtual destructor... extremely important! I'll let you figure out why as an excercise
};
class CChild: public CBase {
public:
void vfunc() { std::cout << "CChild::vfunc()" << std::endl; }
~CChild(){} // Is this destructor called? When? Try adding some std::cout to each destructor
};
int main()
{
CBase *ptr1 = new CBase;
CBase *ptr2 = new CChild;
ptr1->vfunc(); // ptr1 points to an instance of CBase. This is what's important!!
ptr2->vfunc(); // ptr2 points to an instance of CChild, which can be referenced to as a CBase
delete ptr1;
delete ptr2;
}
Output:
CBase::vfunc()
CChild::vfunc()
PS: I just realised I'm about 5 years late to the party, but since I find educational value on this I'll post it anyways!
来源:https://stackoverflow.com/questions/11907507/how-to-call-virtual-function-of-derived-class-through-base-class-pointer