C++含有虚函数类对象模型(一)——父类对象模型

一. 示例代码

Father.h

#ifndef TEST1__FATHER_H_
#define TEST1__FATHER_H_

class Father {
 public:
  virtual void func_1();
  virtual void func_2();
  virtual void func_3();
 private:
  int x = 1;
  int y = 2;
};

#endif //TEST1__FATHER_H_

Father.cpp

#include "Father.h"
#include <iostream>

using namespace std;

void Father::func_1() {
  cout << __FUNCTION__ << endl;
}

void Father::func_2() {
  cout << __FUNCTION__ << endl;
}

void Father::func_3() {
  cout << __FUNCTION__ << endl;
}

二. 对应的对象模型

        因为Father类中含有虚函数, 所以Father类所构造的对象中含有一个虚函数的指针, 这个指针指向虚函数表, 其次是定义的成员变量x, y.

  

 三. 验证模型的正确性

        我们需要将father对象的前面8个字节取出来

        方法如下: 

long long *vptr = (long long *)*(long long *)(&father);

        &father(对father对象取地址时), 得到一个地址值, 这个地址值指向对象的首地址, 代表了长度为16字节的内存单元, 我们现在需要取内存的前面8个字节, 所以我们将Father *类型强制转换为long long *类型(long long类型一般都为8个字节), 经过这一步操作后, 再进行一次解引用, 即*(long long *)(&father)后, 得到了虚函数表中func1的实际地址. 解引用之后, 得到的指针并非为long long类型, 所以此时我们将解引后的地址强制转换为long long类型, 即上面所写代码.

        至此, 我们已经获得了一个long long类型的地址, 但是这个地址并不能执行函数, 当然是这样, 在64位机器中, 指针的长度为8个字节, 不管什么类型的指针(包括void *)都为8个字节, 计算机是通过指针的类型才可以完成相应的操作, 所以我们需要将我们获得的vptr转换成void (*p)(void)这样的函数指针才可以执行对应的虚函数.(ps.如果是32位机, 指针为4字节, 使用int替换long long)

test.cpp

#include "Father.h"
#include <iostream>
typedef void (*fun_c)(void);
using namespace std;

int main() {
  Father father;
  long long *vptr = (long long *)*(long long *)(&father);
  for (int i = 0; i < 3; i++) {
    ((fun_c)(*vptr++))();
  }
  return 0;
}

 

        接下来, 我们需要访问x, y两个元素(通过father对象并不可以访问, 因为成员变量为private)

        方法如下:        

#include "Father.h"
#include <iostream>
using namespace std;

int main() {
  Father father;
  for (int i = 0; i < 2; i++) {
    cout << *(int *)((long)(&father) + 8 + 4 * i) << endl;
  }
  return 0;
}

        先将father对象的地址转化为一个long类型的数字, +8字节跳过虚函数表指针, (4 * i) 当第一轮输出时,i为0, 输出刚好为x的值, 第二轮循环时, +4个字节, 此时刚好输出y的值.

         结果为:

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值