class A {
public:
virtual void vfunc1();
virtual void vfunc2();
void func1();
void func2();
virtual ~A();
private:
int m_data1, m_data2;
}; class B : A {
public:
virtual void vfunc1();;
void func2();
virtual ~B();
private:
int m_data3;
}; class C : B {
public:
virtual void vfunc1();
void func();
private:
int m_data1, m_data4;
};

注:在子类中出现与父类相同名称的变量和非虚函数不是最佳实践,这里是为了说明其内存结构。

对其分析如下:

1. 每个含有虚函数的类在内存中多一根指针(vptr),见图中a,b,c对象中第一个位置,存储的是虚函数表(vtbl)所在的位置。

2. 虚函数表(vtbl)存储着所有虚函数的位置(地址),由于其动态绑定特性,在覆写(override)后在子类中存储的虚函数位置与父类中不相同。

3. 分析上述代码, B继承A,所以A中的数据部分也被B继承下来,同时B添加上了自己的数据部分m_data3,加之vptr,组成了B左侧的内存布局。

  A中的虚函数vfunc1(),vfunc2()可以被覆写和动态绑定。

  所以在B中,vfunc1()被覆写,其vtbl中对应项指向了新的函数的位置(亮蓝色)。vfunc2()未被覆写,仍然指向原先位置(深蓝色)。

  C与B同理,vfunc1()被覆写,其vtbl中对应项指向了新的函数的位置(橘黄色)。vfunc2()未被覆写,仍然指向原先位置(深蓝色)。

非虚函数静态绑定,存储在单独的内存空间(code memory section,灰色函数部分),调用时把对象的this指针,传给一个invisible参数,以便确定谁在调用函数。

4. 调用虚函数的语句的C语言形式如图中下部分所示,其中n表示对应的函数在第几个位置(编译器在建立虚函数表的时候已知),从而实现动态绑定。

C++对象内存模型2 (虚函数,虚指针,虚函数表)(转)的更多相关文章

  1. C++对象内存模型2 (虚函数,虚指针,虚函数表)

    从例子入手,考察如下带有虚函数的类的对象内存模型: class A { public: virtual void vfunc1(); virtual void vfunc2(); void func1 ...

  2. 从零开始学C++之虚继承和虚函数对C++对象内存模型造成的影响

    首先重新回顾一下关于类/对象大小的计算原则: 类大小计算遵循结构体对齐原则 第一个数据成员放在offset为0的位置 其它成员对齐至min(sizeof(member),#pragma pack(n) ...

  3. 对C++对象内存模型造成的影响(类/对象的大小)

    首先重新回顾一下关于类/对象大小的计算原则: 类大小计算遵循结构体对齐原则 第一个数据成员放在offset为0的位置 其它成员对齐至min(sizeof(member),#pragma pack(n) ...

  4. c++ 虚函数和纯虚函数

    在你设计一个基类的时候,如果发现一个函数需要在派生类里有不同的表现,那么它就应该是虚的.从设计的角度讲,出现在基类中的虚函数是接口,出现在派生类中的虚函数是接口的具体实现.通过这样的方法,就可以将对象 ...

  5. C++ - 虚基类、虚函数与纯虚函数

    虚基类       在说明其作用前先看一段代码 class A{public:    int iValue;}; class B:public A{public:    void bPrintf(){ ...

  6. c++中虚函数和纯虚函数定义

    只有用virtual声明类的成员函数,使之成为虚函数,不能将类外的普通函数声明为虚函数.因为虚函数的作用是允许在派生类中对基类的虚函数重新定义.所以虚函数只能用于类的继承层次结构中. 一个成员函数被声 ...

  7. C++ 虚函数 、纯虚函数、接口的实用方法和意义

    也许之前我很少写代码,更很少写面向对象的代码,即使有写多半也很容易写回到面向过程的老路上去.在写面向过程的代码的时候,根本不管什么函数重载和覆盖,想到要什么功能就变得法子的换个函数名字,心里想想:反正 ...

  8. C++多态、虚函数、纯虚函数、抽象类、虚基类

    一.C++多态 C++的多态包括静态多态和动态多态.静态多态包括函数重载和泛型编程,动态多态包括虚函数.静态多态是指在编译期间就可以确定,动态多态是指在程序运行时才能确定. 二.虚函数 1.虚函数为类 ...

  9. 【转】C++ 虚函数&纯虚函数&抽象类&接口&虚基类

    1. 动态多态 在面向对象语言中,接口的多种不同实现方式即为多态.多态是指,用父类的指针指向子类的实例(对象),然后通过父类的指针调用实际子类的成员函数. 多态性就是允许将子类类型的指针赋值给父类类型 ...

  10. C++(九)— 虚函数、纯虚函数、虚析构函数

    1.虚函数 原因:通过指针调用成员函数时,只能访问到基类的同名成员函数.在同名覆盖现象中,通过某个类的对象(指针及引用)调用同名函数,编译器会将该调用静态联编到该类的同名函数,也就是说,通过基类对象指 ...

随机推荐

  1. 【转帖】普通程序员如何转向AI方向

    普通程序员如何转向AI方向 https://www.cnblogs.com/subconscious/p/6240151.html 眼下,人工智能已经成为越来越火的一个方向.普通程序员,如何转向人工智 ...

  2. Delphi 开发微信公众平台 (二)- 用户管理

    一.用户标签管理 开发者可以使用用户标签管理的相关接口,实现对公众号的标签进行创建.查询.修改.删除等操作,也可以对用户进行打标签.取消标签等操作. 1.创建标签 /// <summary> ...

  3. Java的常用API之Object类简介

    Object类 1.toString方法在我们直接使用输出语句输出对象的时候,其实通过该对象调用了其toString()方法. 2.equals方法方法摘要:类默认继承了Object类,所以可以使用O ...

  4. 在Eclipse中使用Beyond Compare做为比较工具

    1.下载org.eclipse.externaltools-Update-0.8.9.v201003051612.zip插件包 接下来,要下载Beyond Compare的插件,http://beyo ...

  5. Tomcat 类加载器的实现

    Tomcat 内部定义了多个 ClassLoader,以便应用和容器访问不同存储库中的类和资源,同时达到应用间类隔离的目的.本文首发于公众号:顿悟源码. 1. Java 类加载机制 类加载就是把编译生 ...

  6. 关于.net core 中的signalR组件的使用

    SignalR是为了提供更方便的web交互响应式到推送式的解决方案.有了它之后可以实现客户端直接调用服务端的方法并且获得返回值 (客户端可以是各种平台,目前SignalR支持的语言版本有C#.java ...

  7. 6、VUE指令

    1.指令的格式 1.1. 指令的概念 指令是指带有v-前缀的特殊属性,指令的职责是当其表达式的值改变时,相应的将某些行为应用到DOM上. 1.2. 指令必须是html的属性 指令只能以带前缀的html ...

  8. C#桌面程序启动时传入参数

    using System;using System.Collections.Generic;using System.Linq;using System.Windows.Forms; namespac ...

  9. Spring AOP 复习

    Aspect Oriented Programming 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术,利用aop可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降 ...

  10. "startIWDP": true

    { "platformName": "iOS", "platformVersion": "11.0", "au ...