频道直达 - 专题 - 新闻 - 技巧 - 组网 - 开发 - 安全 - web编程 - 图像 - 操作系统 - 数据库 - 教育 - 旅游 - 健康 - 时尚 - 驱动 - 软件 - 游戏 - 多媒体 - ERP - 讨论组

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

来源:VCKBASE 作者:李马编译 出处:巧巧读书 2005-12-02 进入讨论组
下一页 1 2 3 4 5 
访问地址 http://www.qqread.com/vc/n782121200.html
  介绍

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

  现在让我们来探究一些虚函数背后更加有趣的资料。为了和上文保持一致,在本文的讨论中我将使用相同的顺序,程序的序号从20开始。

  让我们看看下面这个程序:

  程序20.

#include <iostream>
using namespace std;

class Base {
 public:
  virtual void fun() {
   cout << "Base::fun" << endl;
  }
  void show() {
   fun();
  }
};

class Drive : public Base {
 public:
  virtual void fun() {
   cout << "Drive::fun" << endl;
  }
};

int main() {
 Drive d;
 d.show();

 return 0;
}

  程序的输出为:Drive::fun

  这个程序清楚地示范了基类的函数是如何调用派生类的虚函数的。这一技术被用于不同的框架中,例如MFC和设计模式(比如Template Design Pattern)。现在你可以修改一下这个程序来看看它的行为,我将要在基类的构造函数中调用虚函数,而不是普通的成员函数。

  程序21.

#include <iostream>
using namespace std;

class Base {
 public:
  Base() {
   fun();
  }
 virtual void fun() {
  cout << "Base::fun" << endl;
 }
};

class Drive : public Base {
public:
 virtual void fun() {
  cout << "Drive::fun" << endl;
 }
};

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

  程序的输出为:ase::fun

  这个程序表明,我们不能在基类的构造函数中调用派生类的虚函数。好了,那就让我们来看看着布幔之下到底做了什么。我将会把这些构造函数之中的指针值打印出来,为了简便起见,我移除了类中其它的函数。

  程序22.

#include <iostream>
using namespace std;

class Base {
 public:
  Base() {
   cout << "In Base" << endl;
   cout << "This Pointer = " << (int*)this << endl;
   cout << endl;
  }
  virtual void f() { cout << "Base::f" << endl; }
 };

class Drive : public Base {
 public:
 Drive() {
  cout << "In Drive" << endl;
  cout << "This Pointer = " << (int*)this << endl;
  cout << endl;
 }
 virtual void f() { cout << "Drive::f" << endl; }
};

int main() {
 Drive d;
 cout << "In Main" << endl;
 cout << (int*)&d << endl;
 return 0;
}

  程序的输出为:

In Base
This Pointer = 0012FF7C

In Drive
This Pointer = 0012FF7C

In Main
0012FF7C

  这就表示,整个内存位置中,只有一个对象的存在。那么就让我们把这个指针指向的值打印出来,也就是虚函数表的指针vptr指向的值,VTable的地址。

  程序23.

#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 = " << (int*)*(int*)*(int*)this << endl;
  cout << endl;
 }
 virtual void f1() { cout << "Base::f1" << 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 = " << (int*)*(int*)*(int*)this << endl;
  cout << endl;
 }
 virtual void f1() { cout << "Drive::f2" << endl; }
};

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

  程序的输出为:

In Base
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C08C
Value at Vtable = 004010F0

In Drive
Virtual Pointer = 0012FF7C
Address of Vtable = 0046C07C
Value at Vtable = 00401217

  这个程序示范了基类和派生类中不同的虚函数表地址。为了更好地弄懂这一问题,那就让我们把继承层次加深,并添加一个继承于Drive类的MostDrive类,然后构建一个它的对象。

进入讨论组讨论。
更多专题 【深 度 阅 读】 相 关 文 章
    下一页 1 2 3 4 5 
    收藏此文】【 】【打印】【关闭
    相关图文阅读
    频道图文推荐
    健 康 咨 询
    时 尚 咨 询
    巧巧读书宗旨
    相关专题
    讨论组问题推荐
    站内各频道最新更新文档
    站内最新制作专题
    热门关键字导读
    Photoshop教 程照片处理 照片制作 PS快捷键 抠图
    计 算 机 故 障XP系统修复
    艺 术 与 设 计设计 流媒体 设计欣赏 边框
    计 算 机 安 全ARP
    站内频道文章精选
    巧巧电脑频道编辑信箱  告诉我们您想看的专题或文章