VC驿站

 找回密码
 加入驿站

QQ登录

只需一步,快速开始

有编程疑问吗?还请到提问专区发帖提问!
搜索
查看: 614|回复: 6

[求助] 有关C++的类成员指针的一点小疑问

[复制链接]
08_avatar_middle
在线会员 SummerGull 发表于 2017-8-23 21:35:54 | 显示全部楼层 |阅读模式
3驿站币
本帖最后由 SummerGull 于 2017-8-23 21:35 编辑

虚函数是由一个叫做虚函数表的东西 [vtbl] 这个我清楚
然后 有一点疑问的是 那么  指向 父类虚函数的指针是如何一个过程?
应该是 把 虚函数表里面的虚函数地址 给指针化了?
代码奉上
  1. #include <iostream>
  2. using namespace std;

  3. class father
  4. {
  5. private:
  6.         int x;
  7. public:
  8.         father(int a = 99)
  9.         {
  10.                 x = a;
  11.         }
  12.         virtual void run()
  13.         {
  14.                 cout << "对,我是一头猪 kang~~" << endl;
  15.         }
  16.         virtual void seelp()
  17.         {
  18.                 cout << "对,我很喜欢碎觉 zz~~" << endl;
  19.         }
  20. };
  21. class xu :public father
  22. {
  23. public:
  24.         virtual void run()
  25.         {
  26.                 cout << "对,我是一头猎豹   ~~" << endl;
  27.         }
  28.         virtual void seelp()
  29.         {
  30.                 cout << "对,我很喜欢跑酷 qq~~" << endl;
  31.         }
  32. };

  33. class pei :public father
  34. {
  35. public:
  36.         virtual void run()
  37.         {
  38.                 cout << "对,我是一头大象   ~~" << endl;
  39.         }
  40.         virtual void seelp()
  41.         {
  42.                 cout << "对,我很喜欢踩人 ww~~" << endl;
  43.         }
  44. };
  45. class yu :public father
  46. {
  47. public:
  48.         virtual void run()
  49.         {
  50.                 cout << "对,我是一头川子   ~~" << endl;
  51.         }
  52.         virtual void seelp()
  53.         {
  54.                 cout << "对,我很喜欢唱歌 ee~~" << endl;
  55.         }
  56. };
  57. int main()
  58. {
  59.         /*
  60.         father *a;
  61.         a = new father;
  62.         a->run();
  63.         delete a;

  64.         a = new xu;
  65.         a->run();
  66.         delete a;
  67.        
  68.         a = new pei;
  69.         a->run();
  70.         delete a;

  71.         a = new yu;
  72.         a->run();
  73.         delete a;
  74.         //以上代码不用 这是不用指针 接下来用指针*/
  75.         father *a;
  76.         void (father::*pf)() = 0;
  77.         pf = &father::run;//这局代码的含义是否代表着
  78.         //把父类的函数 赋给 pf
  79.         //这样指针指向的是 父类的函数
  80.         //多态性原则 可以动态运行不同函数
  81.         //那么 也可以指向 子类的 run函数。
  82.         //这里的 函数代表是什么一个意思
  83.         //然后 替换 虚函数表里的函数指针?
  84.        

  85.         a = new father;
  86.         (a->*pf)();
  87.         delete a;

  88.         a = new xu;
  89.         (a->*pf)();
  90.         delete a;

  91.         a = new pei;
  92.         (a->*pf)();
  93.         delete a;

  94.         a = new yu;
  95.         (a->*pf)();
  96.         delete a;

  97.         return 0;
  98. }
复制代码

最佳答案

查看完整内容

之前也没太注意这块,楼主发了这个提问帖子正好我也补一补基础知识。实际上楼主的问题不仅仅是虚函数表的事儿,还有一个知识点就是:通过类成员指针获得成员偏移量。 我举个例子: 例如:一个类 Test 有个 int 型的成员变量 p 和 x; 那么我们就可以通过 int Test::*pOffset = &Test::x 获得该成员变量的偏移量,然后通过: int nOffset = reinterpret_cast(*(void**)(&pOffset)) 就可以将其转化为偏移量的整型数值。你会 ...




上一篇:mfc 通过CFileDialog如何将信息保存为xml文件?
下一篇:问题是如何设置菜单栏中的RecentFiles?

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

51_avatar_middle
online_admins Syc 发表于 2017-8-23 21:35:55 | 显示全部楼层
之前也没太注意这块,楼主发了这个提问帖子正好我也补一补基础知识。实际上楼主的问题不仅仅是虚函数表的事儿,还有一个知识点就是:通过类成员指针获得成员偏移量。
我举个例子:
例如:一个类 Test 有个 int 型的成员变量 p 和 x;
  1. class Test
  2. {
  3. public:
  4.         int p;
  5.         int x;
  6. };
复制代码


那么我们就可以通过 int Test::*pOffset = &Test::x 获得该成员变量的偏移量,然后通过:
int nOffset = reinterpret_cast<int>(*(void**)(&pOffset)) 就可以将其转化为偏移量的整型数值。你会发现这个 nOffset 的值是4,也就是说相对于 Test 类对象实例的首地址偏移 4个字节,为什么是 4 呢?因为在 x 的前面 p 占用 4个字节,所以 nOffset 是4,如果你直接求 p 的偏移量的话,你会发现 nOffset 的值是 0,也就是说相对于 Test 类对象实例的首地址偏移 0个字节。

好了,经过上面的分析楼主应该猜到了,你代码中的这句:pf = &father::run; 相当于 pf 是 run 函数相对于类对象实例的偏移地址。那么大家都知道,类的虚函数表存在于类对象的最前面的地方,也就是首地址的地方。所以根据虚函数表派生类覆盖的原则。当:
a = new father;
(a->*pf)();
这两行代码调用时,实际上是调用 father 对象 a 偏移 pf 位置的函数,那么默认就是 father 中的 run;

当:
a = new xu;
(a->*pf)();
这两行代码调用时,实际上是调用 xu 对象 a 偏移 pf 位置的函数,那么默认就是 xu 中的 run;

依此类推!楼主应该明白了吧。


参考文章:
C++得到成员变量的偏移值:
http://blog.csdn.net/ycf74514/article/details/50063185

C++ 虚函数表解析
http://blog.csdn.net/haoel/article/details/1948051

评分

参与人数 1驿站币 +1 收起 理由
08_avatar_small SummerGull + 1 胜读2本书。

查看全部评分

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复

使用道具 举报

51_avatar_middle
online_admins Syc 发表于 2017-8-23 23:09:27 | 显示全部楼层
不过说实话,楼主研究的这个也只是作为技术研究研究可以,到实际项目中还是直接用指针来调用函数。用偏移的这种形式还是比较少见啊!

点评

恩,当初学了C++现在回头 阅读书本 发现有些问题 不是很参透。百度上说的天花乱坠。  发表于 2017-8-23 23:13

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复

使用道具 举报

08_avatar_middle
ico_lz  楼主| SummerGull 发表于 2017-8-23 23:20:00 | 显示全部楼层
Syc 发表于 2017-8-23 21:35
之前也没太注意这块,楼主发了这个提问帖子正好我也补一补基础知识。实际上楼主的问题不仅仅是虚函数表的事 ...

#define OFFSET(structure, member) ((int)&((structure*)0)->member);
这个 我理解起来 有点,,,能否帮忙解释下。感激不尽

点评

难倒是感觉不难。就是感觉短路了 脑子  发表于 2017-8-23 23:20

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复

使用道具 举报

51_avatar_middle
online_admins Syc 发表于 2017-8-23 23:26:30 | 显示全部楼层
SummerGull 发表于 2017-8-23 23:20
#define OFFSET(structure, member) ((int)&((structure*)0)->member);
这个 我理解起来 有点,,,能 ...

看来楼主对我有依赖了,另外代码不要光用眼睛看,要放到编译器里面去调试!

获取成员变量偏移量的两种方式:

第一种方式是MFC里使用广泛的宏:#define OFFSET(structure, member) ((int)&((structure*)0)->member);
正如我们平时通过某对象的地址指针访问某个成员变量一样,这里只是强制使用0作为该地址,但区别是并没有通过该地址去访问成员变量,而只是用&操作符来获取该成员变量的地址,所以不会出现访问违规的情况。所以,完全可以用此类声明一个对象,然后用该对象某成员变量地址减去该对象首地址获取偏移量,只是纯虚类无法这样实现。

另一种方式是通过域操作符取成员变量的地址。例如一个类Test有int 型成员变量x,则可以通过int Test::* pOffset = &Test::x 获得该偏移量,然后通过int nOffset = reinterpret_cast<int>(*(void**)(&pOffset))将其转化为整型量。

另外,以上这两种方式都对静态成员无效。

发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

如果你已经在论坛发帖求助,并且从坛友或者管理的回复中解决了问题,请编辑帖子并把分类改成【已解决】

如何回报帮助你解决问题的坛友?可以给对方加【热心】【驿站币】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入驿站 qq_login

本版积分规则

关闭

站长提醒上一条 /1 下一条

QQ
QQ在线咨询
联系电话
13591366679
手机扫一扫 关注本站精彩内容
wxqrcode

QQ|小黑屋|手机版|VC驿站 ( 辽ICP备09019393号tongdun|网站地图wx_jqr

GMT+8, 2018-8-19 19:19

Powered by Discuz! X3.4

© 2009-2018 cctry.com

快速回复 返回顶部 返回列表