现在,你会发现在基类中含有多个虚函数的情况下,派生类并不能完全重写它们。
程序26.
#include <iostream> using namespace std;
class Base { public: Base() { cout << "In Base" << endl; cout << "Virtual Pointer = " << (int*)this << endl; cout << "Address of Vtable = " << (int*)*(int*)this << endl; cout << "Value at Vtable 1st entry = " << (int*)*((int*)*(int*)this+0) << endl; cout << "Value at Vtable 2nd entry = " << (int*)*((int*)*(int*)this+1) << endl; cout << "Value at Vtable 3rd entry = " << (int*)*((int*)*(int*)this+2) << endl; cout << endl; } virtual void f1() { cout << "Base::f1" << endl; } virtual void f2() { cout << "Base::f2" << endl; } };
class Drive : public Base { public: Drive() { cout << "In Drive" << endl; cout << "Virtual Pointer = " << (int*)this << endl; cout << "Address of Vtable = " << (int*)*(int*)this << endl; cout << "Value at Vtable 1st entry = " << (int*)*((int*)*(int*)this+0) << endl; cout << "Value at Vtable 2nd entry = " << (int*)*((int*)*(int*)this+1) << endl; cout << "Value at Vtable 3rd entry = " << (int*)*((int*)*(int*)this+2) << endl; cout << endl; } virtual void f1() { cout << "Drive::f1" << endl; } };
int main() { Drive d; return 0; } |
程序的输出为:
In Base Virtual Pointer = 0012FF7C Address of Vtable = 0046C0E0 Value at Vtable 1st entry = 004010F0 Value at Vtable 2nd entry = 00401145 Value at Vtable 3rd entry = 00000000
In Drive Virtual Pointer = 0012FF7C Address of Vtable = 0046C0C8 Value at Vtable 1st entry = 0040121C Value at Vtable 2nd entry = 00401145 Value at Vtable 3rd entry = 00000000 |
这个程序的输出表明基类的虚函数在派生类中并未被重写,然后,派生类的构造函数没有对虚函数的入口做任何的事情。 那么现在,让我邀请纯虚函数来加入这一游戏,再来看看它的行为吧。请看以下的程序:
程序27.
#include <iostream> using namespace std;
class Base { public: Base() { cout << "In Base" << endl; cout << "Virtual Pointer = " << (int*)this << endl; cout << "Address of Vtable = " << (int*)*(int*)this << endl; cout << "Value at Vtable 1st entry = " << (int*)*((int*)*(int*)this+0) << endl; cout << "Value at Vtable 2nd entry = " << (int*)*((int*)*(int*)this+1) << endl; cout << endl; } virtual void f1() = 0; virtual void f2() = 0; };
class Drive : public Base { public: Drive() { cout << "In Drive" << endl; cout << "Virtual Pointer = " << (int*)this << endl; cout << "Address of Vtable = " << (int*)*(int*)this << endl; cout << "Value at Vtable 1st entry = " << (int*)*((int*)*(int*)this+0) << endl; cout << "Value at Vtable 2nd entry = " << (int*)*((int*)*(int*)this+1) << endl; cout << endl; } virtual void f1() { cout << "Drive::f1" << endl; } virtual void f2() { cout << "Drive::f2" << endl; } };
int main() { Drive d; return 0; } |
在debug和release模式下,程序的输出有所不同。下面是debug模式的输出:
In Base Virtual Pointer = 0012FF7C Address of Vtable = 0046C0BC Value at Vtable 1st entry = 00420CB0 Value at Vtable 2nd entry = 00420CB0
In Drive Virtual Pointer = 0012FF7C Address of Vtable = 0046C0A4 Value at Vtable 1st entry = 00401212 Value at Vtable 2nd entry = 0040128F |
以下则是release模式的输出:
In Base Virtual Pointer = 0012FF80 Address of Vtable = 0042115C Value at Vtable 1st entry = 0041245D Value at Vtable 2nd entry = 0041245D
In Drive Virtual Pointer = 0012FF80 Address of Vtable = 00421154 Value at Vtable 1st entry = 00401310 Value at Vtable 2nd entry = 00401380 |
为了更好地弄懂这一原理,我们需要对程序作少许的改动,并尝试使用函数指针来调用虚函数。
程序28.
#include <iostream> using namespace std;
typedef void(*Fun)();
class Base { public: Base() { cout << "In Base" << endl; cout << "Virtual Pointer = " << (int*)this << endl; cout << "Address of Vtable = " << (int*)*(int*)this << endl; cout << "Value at Vtable 1st entry = " << (int*)*((int*)*(int*)this+0) << endl; cout << "Value at Vtable 2nd entry = " << (int*)*((int*)*(int*)this+1) << endl;
// 尝试执行第一个虚函数 Fun pFun = (Fun)*((int*)*(int*)this+0); pFun();
cout << endl; } virtual void f1() = 0; virtual void f2() = 0; };
class Drive : public Base { public: Drive() { cout << "In Drive" << endl; cout << "Virtual Pointer = " << (int*)this << endl; cout << "Address of Vtable = " << (int*)*(int*)this << endl; cout << "Value at Vtable 1st entry = " << (int*)*((int*)*(int*)this+0) << endl; cout << "Value at Vtable 2nd entry = " << (int*)*((int*)*(int*)this+1) << endl; cout << endl; } virtual void f1() { cout << "Drive::f1" << endl; } virtual void f2() { cout << "Drive::f2" << endl; } };
int main() { Drive d; return 0; } |
现在程序的行为在debug和release模式下仍然不同。在debug模式下,它会显示一个运行时错误的对话框:
并且,当你按下“忽略”按钮之后,它会显示下面的对话框:
而在release模式下运行的话,它只会在控制台窗口中输出错误信息:
In Base Virtual Pointer = 0012FF80 Address of Vtable = 0042115C Value at Vtable 1st entry = 0041245D Value at Vtable 2nd entry = 0041245D
runtime error R6025 - pure virtual function call |
|