首页 > 系统相关 >C++ 多重继承下的内存布局

C++ 多重继承下的内存布局

时间:2024-03-20 22:27:32浏览次数:31  
标签:多重 ... int Derived C++ Base1 Base2 内存 class

1. 多重继承

多重继承示例代码如下:

class Base1 {
public:
    void f0() {}
    virtual void f1() {}
    int a;
};

class Base2 {
public:
    virtual void f2() {}
    int b;
};

class Derived : public Base1, public Base2 {
public:
    void d() {}
    void f2() {}  // override Base2::f2()
    int c;
};

int main() {
    Base2 *b2 = new Base2;
    Derived *d = new Derived;
}

class Derived对象有两个vptr,那么有没有可能将这俩vptr合并成一个呢?

答案是不行。这是因为与单继承不同,在多继承中,class Base1class Base2相互独立,它们的虚函数没有顺序关系,即f1和f2有着相同对虚表起始位置的偏移量,所以不可以按照偏移量的顺序排布;并且class Base1class Base2中的成员变量也是无关的,因此基类间也不具有包含关系;这使得class Base1class Base2class Derived中必须要处于两个不相交的区域中,同时需要有两个虚指针分别对它们虚函数表索引

 2. top offset

在上节Derived的虚函数表中,有两个top offset,其值分别为0和-16,那么这个offset起什么作用呢?

在此,先给出结论:将对象从当前这个类型转换为该对象的实际类型的地址偏移量

仍然以前面的class Derived为例,其虚函数表布局如下:

Vtable for Derived
Derived::_ZTV7Derived: 7u entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI7Derived)
16    (int (*)(...))Base1::f1
24    (int (*)(...))Derived::f2
32    (int (*)(...))-16
40    (int (*)(...))(& _ZTI7Derived)
48    (int (*)(...))Derived::_ZThn16_N7Derived2f2Ev

为了能方便理解本节内容,我们不妨将Derived虚函数表认为是 class Base1和class Base2两个类的虚函数表拼接而成 。因为是多重继承,所以编译器将先继承的那个认为是 主基类(primary base) ,因此Derived类的主基类就是class Base1。

在多继承中,当最左边的类中没有虚函数时候,编译器会将第一个有虚函数的基类移到对象的开头,这样对象的开头总是有vptr

首先看虚函数表的前半部分,如下:

0     (int (*)(...))0
8     (int (*)(...))(& _ZTI7Derived)
16    (int (*)(...))Base1::f1
24    (int (*)(...))Derived::f2

正是因为编译器将class Base1作为Derived的主基类,并将自己的函数加入其中。从上述可以看出offset为0,也就是说Base1类的指针不需要偏移就可以直接访问Derived::f2()

接着看虚函数表的下半部分:

32    (int (*)(...))-16
40    (int (*)(...))(& _ZTI7Derived)
48    (int (*)(...))Derived::_ZThn16_N7Derived2f2Ev

偏移值为-16,因为是多重继承,所以class Base1和class Base2类型的指针或者引用都可以指向class Derived对象,那么又是如何调用正确的成员函数呢?

Base2* b2 = new Derived;
b2->f2(); //最终调用Derived::f2();

由于不同的基类起点可能处于不同的位置,因此当需要将它们转化为实际类型时,this指针的偏移量也不相同,且由于多态的特性,b2的实际类型在编译时期是无法确定的;那必然需要一个东西帮助我们在运行时期确定b2的实际类型,这个东西就是offset_to_top。通过让this指针加上offset_to_top的偏移量,就可以让this指针指向实际类型的起始地址

 

标签:多重,...,int,Derived,C++,Base1,Base2,内存,class
From: https://www.cnblogs.com/love-9/p/18086227

相关文章

  • C++ <atomic>汇编语言实现原理
    C++<atomic>汇编语言实现原理问题我们先看一下这段代码:/**badcnt.c-Animproperlysynchronizedcounterprogram*//*$beginbadcnt*//*WARNING:Thiscodeisbuggy!*/#include"csapp.h"void*thread(void*vargp);/*Threadroutineprototype*//*......
  • C++ 模板入门详解
    目录0.模板引入1.函数模板 1.函数重载的缺点 2.函数模板的概念和格式2. 函数模板的实例化 2.1 隐式实例化:让编译器根据实参推演模板参数的实际类型 2.2 显式实例化:在函数名后的<>中指定模板参数的实际类型2.3函数模板参数的匹配规则 3.类模板 3.1类......
  • C++ 静态变量的初始化线程安全问题
    1.静态变量的初始化线程安全问题C++的局部static变量,是预先在静态存储区分配了内存,然后在第一次执行到这里的时候进行初始化。C++11规定了局部static变量的线程安全,实现上应该是类似std::call_once的实现,我估计基本上就是基于cas的spin-lock,这里当然可以根据编译器不同有不同......
  • 复试C++15真题_程序设计2_递归_输入字符串倒序转整形
    编写一个递归函数,功能为:输入一个字符串,输出一个整数值。例如输入 "1a2xcz34,5a!6" , 输出654321。一开始想不明白怎么写递归,于是我写了迭代的函数。意识到,递归的过程就是实现了迭代的循环,而循环内的操作本质没有太大差别。于是就写出来了:#include<iostream>usingnam......
  • C++ 引用底层解析
    1.引用的底层原理解析引用被称为变量的别名,它不能脱离被引用对象独立存在,这是在高级语言层面的概念和理解,并未揭示引用的实现方式。常见错误说法是“引用“自身不是一个变量,甚至编译器可以不为引用分配空间。引用地址空间存放的是被引用对象的地址。实际上,引用本身是一个变量,......
  • C++ extern
    extern有两个作用:当它与”C”一起连用时,如:extern“C”voidfun(inta,intb);则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的。C++语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称,而C语言则不会,因......
  • C++初阶:初识模板
        在之前的C与C++编程中,针对实现同样类型功能的函数我们学会使用了函数重载,终于可以不用记忆多个功能相同但是函数名不同的函数了喵。但是在实现的时候仍然显得有点不太方便,有些冗余。世界是懒人的世界,为了方便懒人的使用,模板应运而生~目录一、引子二、函数模......
  • 复试C++14真题 看程序写结果5 虚函数、继承 易错?
    复试C++14真题 看程序写结果5  虚函数、继承#include<iostream>usingnamespacestd;classA{public:virtualvoidprint(){cout<<"A::print"<<endl;}//voidprint(){cout<<"A::print"<<endl;}};classB:public......
  • (C++20) jthread中stop_token的基础使用
    (C++20)jthread中stop_token的基础使用文章目录(C++20)jthread中stop_token的基础使用C++20jthread使用方式循环判断条件变量condition_variable_anystop回调std::stop_callbackENDC++20jthreadstd::jthread-cppreference.comstd::stop_token-cpprefere......
  • [转帖]JVM优化之调整大内存分页(LargePage)
    https://nowjava.com/article/31311 在这篇文章中:内存分页大小对性能的提升原理调整OS和JVM内存分页cat/proc/meminfo|grepHugeecho4294967295>/proc/sys/kernel/shmmaxecho154>/proc/sys/vm/nr_hugepages本文将从内存分页的原理,如何调整分页大小两节......