我们先来看一段代码:

 #include <iostream>

 using namespace std;
class A
{
public:
int a;
A( )
{
printf("A:A()的this指针是%p\n", this);
} void funcA( )
{
printf("A:funcA()的this指针是%p\n", this);
}
}; class B
{
public:
int b;
B( )
{
printf("B:B()的this指针是%p\n", this);
} void funcB( )
{
printf("B:funcB()的this指针是%p\n", this);
}
}; class C :public A, public B
{
public:
int c;
C( )
{
printf("C:C()的this指针是%p\n", this);
}
void funcC()
{
printf("C:funcC()的this指针是%p\n", this);
}
}; int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
cout << sizeof(C) << endl; C cobj; cobj.funcA();
cobj.funcB();
cobj.funcC();
return ;
}

运行结果为:

第一个基类子对象A的起始地址是与派生类对象C是重合的。我们来看一张图片:

  上图演示了this指针是如何调整的。在派生类的对象中,基类是作为派生类的子对象存在的,称为基类子对象,当派生类只继承于一个基类时,基类子对象的起始地址是与派生类对象相同的,而当派生类同时继承于多个基类时(多重继承,这里暂时不考虑虚拟继承)

第一个基类子对象的起始地址是与派生类对象重合的,而后续基类子对象的起始地址与派生类对象依次相差前面的基类子对象的长度,比如,D同时派生于A、B、C。D对象的起始地址是0,那么A子对象的起始地址也是0,B子对象的起始地址是0+sizeof(A),而C对象的起始地址为0 + sizeof(A) + sizeof(B)。上面的例子C类派生于A,B。C类对象的地址是006FFD4C,那么A子对象的起始地址和C类对象的起始地址是一样的为006FFD4C,B类对象的起始地址为006FFD4C + sizeof(A) = 006FFD4C + 4 = 006FFD50

如果我们把程修改成如下,输入结果会怎么样呢?

 #include <iostream>

 using namespace std;
class A
{
public:
int a;
A( )
{
printf("A:A()的this指针是%p\n", this);
} void funcA( )
{
printf("A:funcA()的this指针是%p\n", this);
}
}; class B
{
public:
int b;
B( )
{
printf("B:B()的this指针是%p\n", this);
} void funcB( )
{
printf("B:funcB()的this指针是%p\n", this);
}
}; class C :public A, public B
{
public:
int c;
C( )
{
printf("C:C()的this指针是%p\n", this);
}
void funcC()
{
printf("C:funcC()的this指针是%p\n", this);
}
void funcB()
{
printf("C:funcB()的this指针是%p\n", this); //新增加的代码
}
}; int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
cout << sizeof(C) << endl; C cobj; cobj.funcA();
cobj.funcB();
cobj.funcC();
return ;
}

输出结果为:

可以看到,此时三个值都相同了,C类override基类子对象B的funcB函数,此时funB()中的this指针指向C对象的起始地址。

this指针的调整的更多相关文章

  1. 《C与指针》第十一章练习

    本章问题 1.在你的系统中,你能够声明的静态数组最大的长度能达到多少?使用动态内存分配,你最大能获取的内存块有多少? answer: This will vary from system to sys ...

  2. c/c++: c++继承 内存分布 虚表 虚指针 (转)

    http://www.cnblogs.com/DylanWind/archive/2009/01/12/1373919.html 前部分原创,转载请注明出处,谢谢! class Base  {  pu ...

  3. 从汇编看c++成员函数指针(二)

    下面先看一段c++源码: #include <cstdio> using namespace std; class X { public: virtual int get1() { ; } ...

  4. 从汇编看c++多重继承中this指针的变化

    先来看一下下面的c++源码: #include <iostream> using namespace std; class X { public: virtual void print1( ...

  5. C语言精要总结-指针系列(一)

    考虑到指针内容繁多,这里将指针作为一个系列,从简入繁,一点一点深挖并掌握这C语言的精华.初步计划如下 此文为指针系列第一篇: C语言精要总结-指针系列(一) 内存与地址 我们可以把内存看做一排连续的房 ...

  6. 虚函数指针sizeof不为sizeof(void*)

    ref:http://bbs.csdn.net/topics/360249561 一个继承了两个虚基类又增加了自己的一个虚函数pif的类,sizeof(指向pif的指针)竟然是8(X86).我是从这里 ...

  7. 成员函数指针与高效C++委托 (delegate)

    下载实例源代码 - 18.5 Kb 下载开发包库文件 - 18.6 Kb 概要 很遗憾, C++ 标准中没能提供面向对象的函数指针. 面向对象的函数指针也被称为闭包(closures) 或委托(del ...

  8. 关于C++中的非静态类成员函数指针

    昨天发现了一个问题,就是使用对类中的非静态成员函数使用std::bind时,不能像普通函数一样直接传递函数名,而是必须显式地调用&(取地址),于是引申出我们今天的问题:非静态类成员函数指针和普 ...

  9. SplayTree伸展树的非递归实现(自底向上)

    Splay Tree 是二叉查找树的一种,它与平衡二叉树.红黑树不同的是,Splay Tree从不强制地保持自身的平衡,每当查找到某个节点n的时候,在返回节点n的同时,Splay Tree会将节点n旋 ...

随机推荐

  1. 【转】每天一个linux命令(52):ifconfig命令

    原文网址:http://www.cnblogs.com/peida/archive/2013/02/27/2934525.html 许多windows非常熟悉ipconfig命令行工具,它被用来获取网 ...

  2. C#读取Mysql blob字段 (转帖)

    http://blog.csdn.net/config_man/article/details/6123191 开发环境:Windows XP Professional SP3.VS2008.Winf ...

  3. vuex基本熟悉与使用

    vuex的入门与使用讲解 官网:https://vuex.vuejs.org/zh/guide/state.html 定义:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式 ...

  4. Exchange 2003服务器中如何在公司资料夹中设置共享行事历

    Exchange 2003服务器中如何在公司资料夹中设置共享行事历 编写人:左丘文 2018-2-23 春节假期归来,开工第一天,感觉还没有从假期中恢复及调整过来.突然想到了我已经荒废了近一年的园子, ...

  5. 在doc下面执行zpl语言 Copy 文件名 lpt1

    在doc下面执行zpl语言 Copy 文件名 lpt1 测试斑马条码打印机并口是否能正常通讯: 1.Zebra打印机安装好标签和碳带,且打印机进入Ready状态.2.电脑端用Notepad编写输入如下 ...

  6. 白话 Java Bean

    所谓的Java Bean,就是一个java类,编译后成为了一个后缀名是 .class的文件.这就是Java Bean,不就是Java类吗? 1. 什么是 Java Bean? 很多培训机构在讲java ...

  7. json_encode 中文 null

    今天使用json_encode 结果中文变成了null 原来是编码的问题. 将编码由 GBK 转成utf-8的就可以了 iconv('gb2312','utf-8', '中文');

  8. android 关于 webview 控制其它view的显示 以及更改view数据失败的问题总结

    总结: 1.webview 无法直接更改view的属性,可以通过 handler实现,因为跨线程 2.webview可以通过js api读取 view的属性值 代码: private Handler ...

  9. Java堆外内存之二:堆外内存使用总结

    目录: <堆外内存操作类ByteBuffer> <DirectBuffer> <Unsafe(java可直接操作内存(),挂起与恢复,CAS操作)> 有时候对内存进 ...

  10. Neutron 理解 (2): 使用 Open vSwitch + VLAN 组网 [Neutron Open vSwitch + VLAN Virtual Network]

    学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...