设为首页 加入收藏

TOP

ATL布幔下的秘密之虚函数背后的东西(五)
2012-11-04 15:06:41 来源: 作者: 【 】 浏览:925
Tags:ATL 秘密 函数 背后 东西
  程序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的秘密。
首页 上一页 2 3 4 5 下一页 尾页 5/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇ATL布幔下的秘密之模板技术 下一篇ATL布幔下的秘密之内部工作方式

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: