首页 > 编程语言 >C++ 对象模型

C++ 对象模型

时间:2024-03-21 13:22:57浏览次数:31  
标签:BaseA Derive FuncB 对象 模型 C++ int Base void

1. 普通类对象是什么布局?

struct Base {
    Base() = default;
    ~Base() = default;

    void Func() {}

    int a;
    int b;
};

int main() {
    Base a;
    return 0; 
}

2. 带虚函数的类对象是什么布局?

struct Base {
    Base() = default;
    virtual ~Base() = default;

    void FuncA() {}

    virtual void FuncB() {
        printf("FuncB\n");
    }

    int a;
    int b;
};

int main() {
    Base a;
    return 0; 
}

这个含有虚函数的结构体大小为16,在对象的头部,前8个字节是虚函数表的指针,指向虚函数的相应函数指针地址,a占4个字节,b占4个字节,总大小为16。

offset_to_top(0):表示当前这个虚函数表地址距离对象顶部地址的偏移量,因为对象的头部就是虚函数表的指针,所以偏移量为0。

RTTI指针:指向存储运行时类型信息(type_info)的地址,用于运行时类型识别,用于typeid和dynamic_cast

3. 单继承下不含有覆盖函数的类对象是什么布局?

struct Base {
    Base() = default;
    virtual ~Base() = default;

    void FuncA() {}

    virtual void FuncB() {
        printf("Base FuncB\n");
    }

    int a;
    int b;
};

struct Derive : public Base{
public:
    int c;
};

int main() {
    Base a;
    Derive d;
    return 0; 
}

这里的FuncB函数,还是Base类中的FuncB,因为在子类中没有重写这个函数,那么如果子类重写这个函数后对象布局是什么样的,请继续往下看。

4. 单继承下含有覆盖函数的类对象是什么布局?

struct Base {
    Base() = default;
    virtual ~Base() = default;

    void FuncA() {}

    virtual void FuncB() {
        printf("Base FuncB\n");
    }

    int a;
    int b;
};

struct Derive : public Base{
    void FuncB() override {
        printf("Derive FuncB \n");
    }
    int c;
};

int main() {
    Base a;
    Derive d;
    return 0; 
}

注意这里虚函数表中的FuncB函数已经是Derive中的FuncB啦,因为在子类中重写了父类的这个函数。

再注意这里的RTTI中有了两项表示Base和Derive的虚表地址是相同的,Base类里的虚函数和Derive类里的虚函数都在这个链条下。

5. 多继承下不含有覆盖函数的类对象是什么布局?

struct BaseA {
    BaseA() = default;
    virtual ~BaseA() = default;

    void FuncA() {}

    virtual void FuncB() {
        printf("BaseA FuncB\n");
    }

    int a;
    int b;
};

struct BaseB {
    BaseB() = default;
    virtual ~BaseB() = default;

    void FuncA() {}

    virtual void FuncC() {
        printf("BaseB FuncC\n");
    }

    int c;
    int d;
};

struct Derive : public BaseA, public BaseB{
};

int main() {
    BaseA a;
    Derive d;
    return 0; 
}

offset_to_top(0)表示当前这个虚函数表(BaseA,Derive)地址距离对象顶部地址的偏移量,因为对象的头部就是虚函数表的指针,所以偏移量为0。

再注意这里的RTTI中有了两项,表示BaseA和Derive的虚表地址是相同的,BaseA类里的虚函数和Derive类里的虚函数都在这个链条下,截至到offset_to_top(-16)之前都是BaseA和Derive的虚函数表。

offset_to_top(-16)表示当前这个虚函数表(BaseB)地址距离对象顶部地址的偏移量,因为对象的头部就是虚函数表的指针,所以偏移量为-16,这里用于this指针偏移,下一小节会介绍。

注意下后面的这个RTTI:只有一项,表示BaseB的虚函数表,后面也有两个虚析构函数。

6. 多继承下含有覆盖函数的类对象的是什么布局?

struct BaseA {
    BaseA() = default;
    virtual ~BaseA() = default;

    void FuncA() {}

    virtual void FuncB() {
        printf("BaseA FuncB\n");
    }

    int a;
    int b;
};

struct BaseB {
    BaseB() = default;
    virtual ~BaseB() = default;

    void FuncA() {}

    virtual void FuncC() {
        printf("BaseB FuncC\n");
    }

    int c;
    int d;
};

struct Derive : public BaseA, public BaseB{
    void FuncB() override {
        printf("Derive FuncB \n");
    }

    void FuncC() override {
        printf("Derive FuncC \n");
    }
};

int main() {
    BaseA a;
    Derive d;
    return 0; 
}

7. 多继承中不同的继承顺序产生的类对象布局相同吗?

struct BaseA {
    BaseA() = default;
    virtual ~BaseA() = default;

    void FuncA() {}

    virtual void FuncB() {
        printf("BaseA FuncB\n");
    }

    int a;
    int b;
};

struct BaseB {
    BaseB() = default;
    virtual ~BaseB() = default;

    void FuncA() {}

    virtual void FuncC() {
        printf("BaseB FuncC\n");
    }

    int c;
    int d;
};

struct Derive : public BaseB, public BaseA{
    void FuncB() override {
        printf("Derive FuncB \n");
    }

    void FuncC() override {
        printf("Derive FuncC \n");
    }
};

int main() {
    BaseA a;
    Derive d;
    return 0; 
}

BaseB的虚函数表指针和数据在上面,BaseA的虚函数表指针和数据在下面,以A,B的顺序继承,对象的布局就是A在上B在下,以B,A的顺序继承,对象的布局就是B在上A在下。

标签:BaseA,Derive,FuncB,对象,模型,C++,int,Base,void
From: https://www.cnblogs.com/love-9/p/18087157

相关文章

  • 构造方法、private - 私有化、this - 本对象、封装 -set、get方法、分包
     1.构造方法含义:与类名相同,且没有返回项的方法作用:1.和new关键字一起是创建对象:比如Personp=newPerson()2.初始化数据:Personp=newPerson("张三",'男',23);注意:1.创建对象的过程称之为实例化2.一般系统会默认实现无参构造,但是如果类中有有参构造,系统......
  • c++模板
    前言大家好,我是jiantaoyab,这篇文章给大家带来c++模板的介绍,模板是泛型程序设计的基础,模板就是类或者函数的蓝图,后一篇文章我将开始介绍STL,模板在STL中大量的运用。模板分为函数模板和类模板函数模板格式template<typenameT1,typenameT2,......,typenameTn>//参数......
  • LLM进阶——预训练语言模型
    文章目录一、概念二、GPT1、概念2、自回归3、zero-shot三、bert1、概念2、maskedLM一、概念最早的预训练语言模型(plms)是word2vec,现在的模型(gpt&bert)都是基于transformer以下是一些常见的预训练语言模型分类:基于Transformer的模型:BERT(BidirectionalEncoder......
  • C++ 合成默认构造函数
    问题:C++面向对象编程时,如果我们没有声明任何构造函数constructor,按照以前最初学习,说编译器会自动合成一个默认的无参构造函数defaultconstructor,但是事实确实是这样吗,存不存在例外呢,即使有合成构造函数,那么它又将对类数据进行怎样的初始化呢?1.问题一如果我们没有声明任何构造......
  • 3、模板渲染及对象属性访问
    代码如下:fromflaskimportFlask,render_templateapp=Flask(__name__)#定义类用于参数传递classUser:"""对于参数age是后续加上去的,因为前期已经对于类进行过实例化了,所以在增加参数时,最好给上一个默认值.不然之前的写法都要重新修改."""......
  • C++ RTTI
    1.背景RTTI的英文全称是"RuntimeTypeIdentification",中文称为"运行时类型识别",它指的是程序在运行的时候才确定需要用到的对象是什么类型的。用于在运行时(而不是编译时)获取有关对象的信息。在C++中,由于存在多态行为,基类指针或者引用指向一个派生类,而其指向的真正类型,在编译阶......
  • C++标准库容器选择
    C++标准库提供了多种容器,每种容器都有其自身的特点和适用场景。以下是C++标准库中常用的容器以及它们的特点:std::vector:动态数组,支持随机访问,适用于需要快速随机访问元素的场景。std::list:双向链表,支持快速插入和删除操作,适用于需要频繁插入和删除元素的场景。std::deque......
  • Java基础内容:第七章面向对象(下)编程题详解
            建了一个群:908722740 ,欢迎小伙伴门的加入,平时可以互相学习交流,不管是学习还是工作上的都可以多多交流,本人在校学生,技术有限,错误的地方欢迎指正。目录一、多态案例素材【1】乐手弹奏乐器【2】比萨制作【3】购买饮料二、接口案例素材【1】兔子和青蛙【......
  • Java 面向对象编程进阶四(多态、抽象方法抽象类)
    目录多态(polymorphism)多态和类型转换对象的转型(casting) 类型转换异常向下转型中使用instanceof final关键字抽象方法和抽象类抽象类和抽象方法的基本用法多态(polymorphism)        多态指的是同一个方法调用,由于对象不同可能会有不同的行为。现实......
  • Java 面向对象编程进阶六(内部类 )
    目录内部类内部类的概念内部类的分类1、非静态内部类(外部类里使用非静态内部类和平时使用其他类没什么不同)2、静态内部类3、匿名内部类4、局部内部类内部类        内部类是一类特殊的类,指的是定义在一个类的内部的类。实际开发中,为了方便的使用外部类的相......