C++对象模型(8)-- 数据语义学:this指针

news2024/9/25 9:37:48

1、this指针的认识

this 是 C++ 中的一个关键字,也是一个 const 指针 ,它指向当前对象,通过它可以访问当前对象的所有成员。所谓当前对象,是指正在使用的对象。

假如有这么一个类:

class Base {
public:
    int b_i;
    int b_j;

    void print() {
        printf(" this的地址:%p\n", this);
    }
};

那么这个Base类对象的this指针指向的就是变量b_i的地址。

2、没有虚函数的情况

this指针调整一般存在于多重继承的情况下。

我们先进行代码演示:

class X {
public:
    int x_i;

    X() {
        cout << " X::X()的this指针是:" << this << endl;
    }

    void funcX() {
        cout << " X::funcX()的this指针是:" << this << endl;
    }
};

class Y {
public:
    int y_i;

    Y() {
        cout << " Y::Y()的this指针是:" << this << endl;
    }

    void funcY() {
        cout << " Y::funcY()的this指针是:" << this << endl;
    }
};

class Z : public X, public Y {
public:
    int z_i;

    Z() {
        cout << " Z::Z()的this指针是:" << this << endl;
    }

    void funcZ() {
        cout << " Z::funcZ()的this指针是:" << this << endl;
    }
};

int main()
{
    Z z;
    z.funcX();
    z.funcY();
    z.funcZ();
}

类Z对象的内存布局是这样的:

代码的输出结果是这样的:

从输出结果可以画出this指针的指向是下面这样的。

这里有2个要点:

(1) 这里Z类先继承X、再继承Y。派生类Z的地址和第1个继承的基类X的地址是相同的。

(2) 调用哪个子类的成员函数,这个this指针就会被编译器自动调整到对象内存布局中对应类对象的起始地址。

3、父类没有虚函数、子类有虚函数

class X {
public:
    int x_i;

    X() {
        cout << " X::X()的this指针是:" << this << endl;
    }

    void funcX() {
        cout << " X::funcX()的this指针是:" << this << endl;
    }
};

class Y : public X {
public:
    int y_i;

    Y() {
        cout << " Y::Y()的this指针是:" << this << endl;
    }

    void funcY() {
        cout << " Y::funcY()的this指针是:" << this << endl;
    }

    virtual void virFuncY() { }
};

int main()
{
    Y y;

    printf(" 变量a的偏移量:%d\n", &X::x_i);
    printf(" 变量c的偏移量:%d\n", &Y::y_i);

    y.funcX();
    y.funcY();
}

这时输出的结果是这样的:

从输出结果可以看到:

(1) 父类X的this指针比子类X高4个字节,类X的变量x_i的偏移量是0。

这个可以这么理解:虚函数表指针vptr总是在对象的头部,因为父类X没有虚函数表指针,所以父类X对象的指针要往下跳过vptr(4个字节),然后就直接访问变量x_i,所以x_i的偏移量是0。

(2) 类Y的变量y_i的偏移量是8。因为vptr、int x_i各占4个字节,所以变量y_i的偏移量是 4 + 4 = 8。

4、父类、子类都有虚函数

我们给类X加上虚函数:

virtual void virFuncX() { }

然后看输出结果:

从结果我们可以看到,父类X的this指针和类Y的this指针相同了,且变量x_i的偏移量变成了4。这4个字节是虚函数表指针所占用的空间。

5、多重继承且父类都带虚函数

我们在原来的代码上再添加1个新类Z,且让Z继承自类X、Y:

class Z : public X, public Y {
public:
    int z_i;

    Z() {
        cout << " Z::Z()的this指针是:" << this << endl;
    }

    void funcZ() {
        cout << " Z::funcZ()的this指针是:" << this << endl;
    }
};

int main()
{
    Z z;

    printf(" 变量x_i的偏移量:%d\n", &X::x_i);
    printf(" 变量y_i的偏移量:%d\n", &Y::y_i);
    printf(" 变量z_i的偏移量:%d\n", &Z::z_i);

    z.funcX();
    z.funcY();
    z.funcZ();
}

输出结果:

因为2个父类都有虚函数,所以类Z会继承这2个虚函数表指针。但2个父类X、Y是并级的,对于每一个父类对象来说,它的成员变量都会偏移4个字节。而子类的变量会偏移16个字节。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1074510.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

node中的crypto模块指南

node中的crypto模块指南 加密操作可能很棘手&#xff0c;以至于付费的加密服务公司的存在只是为了确保在代码库中正确实现加密操作。好消息是&#xff0c;只需学习一些知识&#xff0c;我们就可以使用 Node 的内置加密模块免费进行适当的加密。 在本指南中&#xff0c;我们将…

Kickstart:快速、可靠的Linux系统自动安装

1 kickstart介绍 由于安装多台服务器系统需要重复回答多个问题&#xff0c;我们需要一个可以记录这些答案的脚本&#xff0c;自动的去回答问题&#xff0c;该文件叫kickstart脚本 2 环境搭建 2.1 配置软件仓库 2.2 关闭防火墙&#xff0c;搭建DHCP&#xff0c;httpd服务 sy…

JavaScript进阶 第一天笔记

JavaScript 进阶 - 第1天 学习作用域、变量提升、闭包等语言特征&#xff0c;加深对 JavaScript 的理解&#xff0c;掌握变量赋值、函数声明的简洁语法&#xff0c;降低代码的冗余度。 理解作用域对程序执行的影响能够分析程序执行的作用域范围理解闭包本质&#xff0c;利用闭包…

web漏洞-xml外部实体注入(XXE)

web漏洞-xml外部实体注入&#xff08;XXE&#xff09; 目录 web漏洞-xml外部实体注入&#xff08;XXE&#xff09;概念危害检测方法利用方法漏洞利用xxe-lab有回显情况无回显情况 pikachu靶场有回显内容无回显 修复方案 概念 xml可拓展标记语言&#xff1a; xml是一种可拓展的标…

面试经典 150 题 14 —(数组 / 字符串)— 134. 加油站

134. 加油站 方法一 class Solution { public:int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {int minSpare std::numeric_limits<int>::max(); // 初始化最小剩余汽油量为整型的最大值int spare 0; // 当前剩余汽油量int len g…

NSSCTF做题(7)

[第五空间 2021]pklovecloud 反序列化 <?php include flag.php; class pkshow { function echo_name() { return "Pk very safe^.^"; } } class acp { protected $cinder; public $neutron; …

基于Softmax回归的多分类任务

Logistic回归可以有效地解决二分类问题&#xff0c;但在分类任务中&#xff0c;还有一类多分类问题&#xff0c;即类别数C大于2 的分类问题。Softmax回归就是Logistic回归在多分类问题上的推广。 使用Softmax回归模型对一个简单的数据集进行多分类实验。 首先给大家看一下需要的…

【SpringCloud】Ribbon负载均衡原理、负载均衡策略、饥饿加载

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 Ribbon 一、 Ribbon负载均衡原理1.1 负载均…

4.springcloudalibaba sentinel v1.8.6版本服务搭建

文章目录 前言一、sentinel服务端安装1.1 服务端下载1.2 启动sentinel服务 二、客户端使用sentinel2.1.pom增加sentinel包2.2 增加配置2.3 启动服务 三、验证3.1 给hello接口增加流控规则3.2 测试结果如下 总结 前言 前面完成了gateway项目部署并且测试&#xff0c;现在部署搭…

【ONE·C++ || 异常】

总言 主要介绍异常。 文章目录 总言1、C异常1.1、C语言传统的处理错误的方式1.2、异常概念1.3、异常的基本用法1.3.1、异常的抛出和捕获1.3.1.1、异常的抛出和匹配原则1.3.1.2、 在函数调用链中异常栈展开匹配原则 1.3.2、异常的重新抛出1.3.2.1、演示一1.3.2.2、演示二 1.3.3…

滑动窗口算法技巧

大家好&#xff0c;我是 方圆。在我刷了一些滑动窗口相关的题目之后&#xff0c;发现很有技巧性&#xff0c;只要掌握了解题思路&#xff0c;就会很简单&#xff0c;所以我决定用这篇帖子记录一下&#xff0c;也帮助同样在刷滑动窗口相关题目的同学。 使用滑动窗口解决的问题一…

PADS规则设置

一&#xff0e;设置类规则(DRC检测规则) 默认所有类规则设置网络属性分类设置 网络属性附着颜色 选择电源类在DDR中设置非常实用 创建组合 方便模块整旋转移动 二,元件组合 选择组合 旋转组合 CtrlR旋转90&#xff1b;双击旋转任意角度 拆开组合(还独立元件操作) 三,设置过孔…

【java学习】多维数组(10)

文章目录 1. 二维数组 1. 二维数组 二维数组[][]&#xff1a;数组中的数组 格式1&#xff08;动态初始化&#xff09;&#xff1a;int[][] arr new int[3][2]; 解释说明&#xff1a; 定义了名称为arr的二维数组二维数组中有3个一维数组每个一维数组中有2个元素一维数组的名称…

教资面试多烂才不合格 教师资格证面试难度分析

教资面试是否合格&#xff0c;主要取决于考生的表现是否符合教师职业要求和教育教学能力。以下是一些可能导致教资面试不合格的表现&#xff1a; 对教育事业缺乏热情&#xff0c;对所教授的学科不感兴趣&#xff0c;或者对教育工作没有正确的认知。 对学生的关注不足&#xf…

C++学习day3

目录 作业&#xff1a; 1> 思维导图 2>设计一个Per类&#xff0c;类中包含私有成员:姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员:成绩、Per类对象p1&#xff0c;设计这两个类的构造函数、析构函数和拷贝构造函数。 效果图…

【ICer的脚本练习】shell的三剑客:grep/sed/awk

系列的目录说明请见:ICer的脚本练习专栏介绍与全流程目录_尼德兰的喵的博客-CSDN博客 前言 大大小小的脚本我们写了几个了,在上一篇我们借助bashrc简单了解了bash语言的一些语法和组织规则。这一篇呢我们还是回到shell简单看下三个常用命令,毕竟脚本也可以视为复杂的命令尤…

c++运算符

文章目录 运算符位运算符类型转换 运算符 #include<iostream> using namespace std;int main() {// 算术运算符cout << "1 2 " << 1 2 << endl; cout << "1 2 - 3 * 4 " << 1 2 - 3 * 4 << endl;short a…

mfoc-hardnested在visual studio2022编译

1、点击mfoc-hardnested.sln 2、没有clang LLVM (clang-cl) (未安装) 打开installer 点击修改: 单个组件中搜索clang &#xff0c;安装即可 3、编译 4、main函数 5、mfoc-hardnested.exe使用

v-on事件处理指令;简写@事件名

一、v-on 给元素&#xff08;标签&#xff09;绑定事件监听器 oninput、onclick、onchange、onblur等 1、 完整方式v-on:事件名“函数/方法” 2、简写方式事件名“函数/方法”&#xff0c;注意符号不能加冒号“&#xff1a;” input /click/change/blur ..... 代码如下&#xf…

为什么不建议使用SELECT * ?

“不要使用SELECT ”几乎已经成为数据库使用的一条金科玉律&#xff0c;就连很多公司也明确表示不得使用作为查询的字段列表&#xff0c;更是让这条规则拥有了权威的加持。 为什么不建议直接使用SELECT *&#xff1f;我们总得搞清楚这其中的原因吧&#xff0c;不要别人说不建议…