科技行者

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

知识库

知识库 安全导航

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

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

  • 扫一扫
    分享文章到微信

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

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

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

关键字:

  • 评论
  • 分享微博
  • 分享邮件
程序32.

#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 __declspec(novtable) 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;
 }
};

class __declspec(novtable) MostDrive : public Drive {
 public:
 MostDrive() {
  cout << "In MostDrive" << 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 << "MostDrive::f1" << endl; }
 virtual void f2() { cout << "MostDrive::f2" << endl; }
};

int main() {
 MostDrive d;
 return 0;
}

  现在,程序的输出为:

In Base
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0C0
Value at Vtable 1st entry = 00420E50
Value at Vtable 2nd entry = 00420E50

In Drive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0C0
Value at Vtable 1st entry = 00420E50
Value at Vtable 2nd entry = 00420E50

In MostDrive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C0C0
Value at Vtable 1st entry = 00420E50
Value at Vtable 2nd entry = 00420E50

  在MSDN中,对__declspec(novtable)的解释是:它应该使用在纯虚类中。那么,让我们再做一个实验来更好地弄懂这一含义吧。

  程序33.

#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 __declspec(novtable) 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;
 }
};

class __declspec(novtable) MostDrive : public Drive {
 public:
 MostDrive() {
  cout << "In MostDrive" << 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;
  
  // 尝试调用第一个虚函数
  typedef void (*Fun)();
  Fun pFun = (Fun)*((int*)*(int*)this+0);
  pFun();

 }
 virtual void f1() { cout << "MostDrive::f1" << endl; }
 virtual void f2() { cout << "MostDrive::f2" << endl; }
};

int main() {
 MostDrive d;
 return 0;
}

  我们在程序中添加的新东西是:

// 尝试调用第一个虚函数
typedef void (*Fun)();
Fun pFun = (Fun)*((int*)*(int*)this+0);
pFun();

  并且,当我们运行这个应用程序的时候,我们会面对与前一个程序相同的问题——也就是尝试调用虚函数发生的错误。这就意味着虚函数表并未初始化。MostDrive类并不是一个抽象类,所以我们应该从类中移除__declspec(novtable)。

  程序34.

#include <iostream>
using namespace std;

class Base {
 public:
  virtual void f1() = 0;
  virtual void f2() = 0;
};

class __declspec(novtable) Drive : public Base {
};

class MostDrive : public Drive {
 public:
 MostDrive() {

  // 尝试调用第一个虚函数
  typedef void (*Fun)();
  Fun pFun = (Fun)*((int*)*(int*)this+0);
  pFun();
 }
 virtual void f1() { cout << "MostDrive::f1" << endl; }
 virtual void f2() { cout << "MostDrive::f2" << endl; }
};

int main() {
 MostDrive d;
 return 0;
}

  现在,程序就可以正常工作了。它的输出为: MostDrive::f1

  这个属性并不一定只用在ATL的类中,它可以对任何不能创建对象的类使用。同样,它也并不一定非要用在ATL类中,也就是说它可以从ATL类中省略,不过这就意味着这样会产生更多的代码。

  我希望能在下篇文章中探究更多ATL的秘密。

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

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

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