科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件ATL布幔下的秘密之虚函数背后的东西

ATL布幔下的秘密之虚函数背后的东西

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

在本系列的教程中,我要讨论一些ATL的内部工作方式以及它所使用的技术,这是本系列的第二篇文章。

作者:李马编译 来源:VCKBASE 2007年10月19日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
现在,你会发现在基类中含有多个虚函数的情况下,派生类并不能完全重写它们。

  程序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
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章