浅谈C++对象的内存分布和虚函数表

yizhihongxing

C++对象的内存分布和虚函数表是C++中非常重要的一个知识点。在本篇攻略中,我将详细讲解这个知识点,主要包括以下内容:

  1. C++对象的内存分布

  2. 虚函数表的概念

  3. 虚函数表的实现

  4. 示例说明

一、C++对象的内存分布

C++对象在内存中的分布一般包括以下几个部分:

  1. 对象头部分:一般包括虚函数表指针和类型信息指针;

  2. 对象的成员变量部分:对象的所有成员变量都存放在这里;

  3. 对象的函数部分:对象的非虚函数也会被存放在这里。

总的来说,一个C++对象的内存分布可以用下面的图示表示:

   ------------------
   |   VTablePtr     |  ---> 虚函数表指针
   ------------------
   |   TypeInfoPtr   |  ---> 类型信息指针
   ------------------
   |  MemberVar1     |
   |  MemberVar2     |
   |      ...        |  ---> 成员变量
   |  MemberVarN     |
   ------------------
   |  Non-Virtual    |
   |    Func1        |
   |    Func2        |
   |      ...        |  ---> 非虚函数
   |    FuncN        |
   ------------------

二、虚函数表的概念

虚函数表是C++中用于实现多态的一种机制。每个包含虚函数的类都有一个对应的虚函数表,虚函数表中存放着这个类的虚函数的地址。虚函数表是一个指向函数地址数组的指针,数组中存放的是函数地址,每个位置对应一个虚函数。

子类继承了父类中的虚函数,并且可以重写虚函数,如果子类重写了虚函数,则会更新虚函数表中相应的函数地址。

三、虚函数表的实现

虚函数表的实现是由编译器自动完成的,编译器会在类中添加一个隐藏的虚函数表指针成员变量(即上面提到的对象头部分中的虚函数表指针),并且在类的构造函数中初始化这个指针,指向该类的虚函数表。虚函数表指针是一个指向虚函数表的指针。

虚函数表的实现方式可以用下面的示例说明:

#include <iostream>
using namespace std;

class A {
public:
    virtual void foo() { cout << "A::foo()" << endl; }
};

class B : public A {
public:
    virtual void foo() { cout << "B::foo()" << endl; }
    virtual void bar() { cout << "B::bar()" << endl; }
};

int main() {
    B b;
    long long* pVTable = (long long*)(*(long long*)&b);  // 取出b的虚函数表指针
    long long* pFunc = (long long*)*(pVTable + 1);  // 取出B::foo()的地址
    void (*f)() = (void (*)())pFunc;  // 转换为函数指针
    f();  // 调用B::foo()
    return 0;
}

对上述代码的解释:

  1. 程序中定义了两个类ABBA的子类。

  2. B类覆写了父类的虚函数foo(),并且增加了一个新的虚函数bar()

  3. 在程序中定义了一个B类的对象b

  4. 通过*(long long*)&b的方式,获得了b的虚函数表指针。

  5. 对于B类中的foo()函数,它是虚函数,它的函数地址存储在虚函数表中,通过*(pVTable + 1)的方式,取出了B::foo()的地址。

  6. B::foo()的地址转化成函数指针,并且通过指针调用它。

四、示例说明

在下面的示例中,我们定义了一个简单的图形类Shape,它有两个成员变量xy,以及一个纯虚函数area()。由于area()是一个纯虚函数,所以Shape类是一个抽象类,不能直接实例化。

我们又定义了两个派生类RectangleCircle,它们都继承了Shape类,重载了area()函数,分别实现了矩形和圆的面积计算。

#include <iostream>
using namespace std;

class Shape {
public:
    Shape(int x, int y) : x_(x), y_(y) {}
    virtual ~Shape() {}
    virtual double area() = 0;
protected:
    int x_, y_;
};

class Rectangle : public Shape {
public:
    Rectangle(int x, int y, int w, int h) : Shape(x, y), w_(w), h_(h) {}
    virtual double area() override { return w_ * h_; }
private:
    int w_, h_;
};

class Circle : public Shape {
public:
    Circle(int x, int y, int r) : Shape(x, y), r_(r) {}
    virtual double area() override { return r_ * r_ * 3.1415926; }
private:
    int r_;
};

int main() {
    Shape* shapes[] = {
        new Rectangle(0, 0, 10, 20),
        new Circle(0, 0, 5)
    };
    for (auto s : shapes) {
        cout << "Area: " << s->area() << endl;
    }
    return 0;
}

我们通过输出两个图形的面积,来演示多态的效果。

完整的代码可以在这里找到。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅谈C++对象的内存分布和虚函数表 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • C语言传递字符常量的指针

    下面详细讲解一下“C语言传递字符常量的指针”的完整使用攻略。 标准语法 在C语言中,字符常量实际上是一个指向字符数组的指针,因此在函数中传递字符常量时,应该使用指针参数。 void function_name(char *pointer); 其中,function_name为函数名,pointer为字符常量的指针。 示例一 下面以输出字符常量为例进行说明。 …

    C 2023年5月9日
    00
  • C语言完美实现动态数组代码分享

    C语言完美实现动态数组代码分享 简介 动态数组是一种在程序运行时可以动态扩展的数组结构。C语言并没有原生支持动态数组,不过我们可以基于堆内存动态分配的原理,在C语言中实现动态数组。 本文将介绍如何在C语言中完美实现动态数组,并提供代码示例。 分步实现动态数组 1. 分配动态内存 动态数组必须基于堆内存分配实现。我们可以使用标准库中的 malloc 函数动态分…

    C 2023年5月23日
    00
  • php Try Catch异常测试

    让我来详细讲解一下 PHP 中的异常处理机制 Try Catch 的完整攻略。 什么是异常处理 当 PHP 代码执行遇到错误时,会抛出一个异常,通常这时程序就会直接停止运行并输出一些错误信息给开发者。但是,通过使用 PHP 异常处理机制,我们可以自己定义错误处理程序,来捕获和处理这些抛出的异常,避免程序直接崩溃。 使用 Try Catch 机制进行 PHP …

    C 2023年5月23日
    00
  • #FREERTOS的和heap_4内存分配算法

    FreeRTOS的heap_4内存管理算法具有内存碎片合并的功能,可以有效防止内存碎片产生,使用First fit算法,在实现上与C标准库的malloc类似,但是效率更高且能进行碎片合并回收。以下是个人对源码的解析,有空再补充详细。 一、初始化 static void prvHeapInit( void ) { BlockLink_t *pxFirstFre…

    C语言 2023年4月17日
    00
  • C 语言基础教程(我的C之旅开始了)[三]

    C 语言基础教程(我的C之旅开始了)[三] 完整攻略 在这篇文章中,作者主要介绍了C语言中的条件语句——if语句和switch语句。具体的内容包括以下几个方面: 1. if语句 if是C语言中最常用的条件语句之一,在语法上非常简单,格式为: if (表达式) { 代码块; } 其中,表达式可以是任何可以返回值的C表达式,代码块则是需要执行的语句组合。 在文章…

    C 2023年5月23日
    00
  • 操作系统中的Hosts文件工作原理和作用及其详细介绍

    操作系统中的Hosts文件工作原理和作用及其详细介绍 Hosts文件介绍 在计算机网络中,Hosts文件是一个用于存储 IP 地址和主机名(域名)对应关系的纯文本文件,通常位于操作系统的系统目录下,在 Windows 系统中为 C:\Windows\System32\drivers\etc\hosts 文件。该文件是本地DNS的重要组成部分,可以将特定的主机…

    C 2023年5月23日
    00
  • 快速了解Boost.Asio 的多线程模型

    Boost.Asio是一个C++网络编程库,提供异步I/O操作、定时器、线程池等功能,支持多种操作系统和平台。其中,多线程模型是其重要的特征之一,可以提高网络应用程序的并发性能。下面,我们通过以下几个步骤来快速了解Boost.Asio的多线程模型。 1. 简介Boost.Asio的多线程模型 Boost.Asio的多线程模型基于线程池实现,线程池由多个线程组…

    C 2023年5月22日
    00
  • C连接Mysql数据库代码

    当我们需要在C程序中使用MySQL数据库时,我们需要连接MySQL数据库。下面是将C程序连接MySQL数据库的完整攻略。 步骤1:安装MySQL C API 在C程序中使用MySQL数据库,我们需要安装MySQL C API。MySQL提供了C API开发包,我们可以到MySQL官方网站上下载。 步骤2:连接MySQL数据库 连接MySQL数据库前,需要先初…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部