C++虚函数和成员函数内存 this指针问题
father* p=new son;
p->disp(...);
发现有好多人this指针的本质有错误的认识,估计不少人一说起this指针,脑袋立即反应出:那个类里使用的this指针,那么这个指针就是那个类类型咯。其实事实根本不是这样子的,这里修正对this指针的错误理解:
首先,我在这里重申一点:“this”不是变量,是关键字,意味着this指针并不是哪个真实存在的符号/储存空间。所以,this指针没有C++语言范畴里的变量类型。所以我曾说的“子类disp函数的this指针是son*类型”这个说法是错的。this指针即不能说是son*类型也不能说是"father"类型。
当然,可能不少人因此反驳,我在IDE里敲入“this->”后会自动弹出类的成员变量啊,怎么就说this没有类型呢?确实,this指针多多少少跟所在类的类型有关。因此,我也对this指针使用“类型”一词,但是这里“类型”包含下面的两层含义:
- 起始地址(严格来说应该是0偏移地址)。
- 涵盖范围/寻址范围。
因为在机器层面,变量(其实压根就没有什么变量,该叫操作数)除了整型、浮点型之分外,是没有类型的,更没有类成员一说,只有寻址。据此,再进一步说明之前先介绍两个基本常识:(一下全部在X86-64机器VC++编译器范围类讨论)
======================================基本常识分界线=====================================
基本常识1:
类成员是如何访问的?(注:没有特别说明,都不包括静态成员)
当C++被编译成二进制代码后,不考虑什么导出符号、未定义符号之类的,什么变量名就统统消失,那么要访问这些变量,就得通过机器层面的方式:如以某个地址作为标准/基准(起始地址),通过距离这个基准一定量来定位要访问的变量。对于类成员来说,一般是对象首地址+偏移。比如以下这个类:

class A
{
int a;
int b;
virtual void F();
}

他的一个对象aa在内存中的分布如下:(为什么起始地址为F0H?没有为什么,随便定的)
那么假设对象aa的首地址(F0H)保存在寄存器rax中,那么成员a的访问方式为:
rax+8h
同理,成员b的访问方式:
rax+Ch
基本常识2:
什么是继承?
比如如下定义:

struct IA
{
int a;
virtual void F();
void FF();
};
struct B
{
int b;
virtual void G()=0;
};
class Derived:public B,public IA
{
public:
int d;
virtual void F();
void FF();
virtual void G();
};

那么假设有Derived d,d对象的内存分布图如下:

好了,简介完两个基本常识,开始讲this指针的“类型”。
========================================this指针的类型=================================
this指针跟不少人想象的不一样,它的类型由被调用函数决定。它的类型遵循着这两点规则:(途中打勾为首地址。)
1.对于非虚函数,this指针的基准地址为函数定义所在层级对象的首地址,范围为该层级对象始末。
如:IA::FF();
this指针类型是以D0H为首地址,范围是从首地址开始到DFH为止。(其实里面有内存空洞,我们不去纠结这个)
Derived::FF();
this指针类型是C0H为首地址,范围是从首地址到E8H为止。

2.对于虚函数,this指针的基准地址为函数首先声明者的首地址,范围为实现者的始末。
如:IA::F();
其this指针类型是以D0H为首地址,范围是从首地址开始到DFH为止。
Derived::F();
其this指针类型是以D0H为首地址,范围是从C0H到E8H为止。

那么当有IA* a=new Derived();后,
a->F();便是这么访问b成员的了。假设首地址D0H保存在寄存器rax里,
rax-8
========================================结案陈词======================================
好了,这里可以最后总结回答原问题三及其新问的“如果用对象指针调用函数,那么到底是指针传递给this还是&object传递给this?”
之所以有人所疑惑的“this指针到底是father*还是son*”,秘密就在这里。之所以觉得它像是father*,是因为形如IA* a=new Derived();a所存放的地址是D0H,通过a所能直接访问的范围限于上面的橙色区域,并且当调用F()时,所传的地址、this指针的值就是a的值D0H。而又觉得它是son*,是因为在F()内部,通过this指针可以访问的范围值整个子类对象。于是乎就让人觉得有父类指针隐式转换为子类指针之嫌。
C++虚函数和成员函数内存 this指针问题的更多相关文章
- C++基础 (4) 第四天 this指针 全局函数和成员函数 友元 操作符重载
1static强化练习-仓库进货和出货 #define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std; c ...
- c++-变量,this指针,全局函数,成员函数,自定义数组类
区分变量属于哪个对象 c++对象管理模型初探 C++类对象中的成员变量和成员函数是分开存储的,C中内存四区仍然有效 C++编译器对普通成员函数的内部处理(隐藏this指针) this指针解决函数形参和 ...
- golang写业务代码,用全局函数还是成员函数
在golang中,函数划分为全局函数和成员函数,在使用的时候,有种情况,会产生一些疑惑的,就是在写业务代码的时候,使用全局函数好像会比较方便,一般业务代码,都不会复用,都是针对特定的业务进行编程,要复 ...
- C++ 1//设计立方体类 //创建立方体的类 //设计属性和行为 //获取立方体的面积和体积 //分别利用(全局函数 和 成员函数)判断俩个立方体是否相等
1 //设计立方体类 2 //创建立方体的类 3 //设计属性和行为 4 //获取立方体的面积和体积 5 //分别利用(全局函数 和 成员函数)判断俩个立方体是否相等 6 #include <i ...
- C++调用动态库中的虚基类成员函数时总是进错函数
原创文章,转载请注明作者与本文原始URL. 问题描述:最近遇到这样一个问题,在调用C++的一个成员函数时,总是进错函数.在调用 pMsg->GetMsgContent() 的时候,总是进入到 p ...
- C++多态实现(虚函数,成员函数覆盖、隐藏)
// 1.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> using namespace ...
- 全局函数VS成员函数
#include <iostream> using namespace std; class Test { public: Test(int a, int b) { this->a ...
- C++(三十三) — 全局函数、成员函数的区别
区别: (1)全局函数的参数个数,比局部函数要多一个: (2)二者都可,返回元素.返回引用. class test { public: test(int a, int b) { this->a ...
- C++之全局函数和成员函数互相转换
解析:成员函数会用this指针自动隐藏第一个操作数(左操作数) 1.把全局函数转化成成员函数,通过this指针隐藏左操作数. Test add(Test &t1,Test &t2) ...
- C++走向远洋——34(友元函数,成员函数和一般函数的区别)
*/ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:youyuan.cpp * 作者:常轩 * 微信公众号:Worl ...
随机推荐
- 论文阅读:Adaptive NMS: Refining Pedestrian Detection in a Crowd
论文阅读:Adaptive NMS: Refining Pedestrian Detection in a Crowd 2019年04月11日 23:08:02 Kivee123 阅读数 836 ...
- C#基础知识 (转)
https://www.cnblogs.com/zhouzhou-aspnet/articles/2591596.html(原文地址) 本文是一个菜鸟所写,本文面向的人群就是像我这样的小菜鸟,工作一年 ...
- Django数据查询中对字段进行排序
Django数据查询中对字段进行排序 第一种方法:使用order_by进行排序 Articlelist = Article.objects.filter(**kwargs).order_by('n ...
- selenium无头浏览器&规避操作
一.无头浏览器概述: 无头浏览器主要目的是打开浏览器但用户看不到 简单用法如下: from selenium import webdriver from time import sleep from ...
- 开源跨境ERP - 小老板 Docker/Docker Compose一键部署
先上部署成功后的截图,各个菜单点击均无报错 DockerCompose 包含: 1. 三个mysql5.7数据库 2. redis php会话存储+ memcached 3. 小老板php主程序 do ...
- 常见python面试题-手写代码系列
1.如何反向迭代一个序列 #如果是一个list,最快的方法使用reversetempList = [1,2,3,4]tempList.reverse()for x in tempList: pr ...
- kubernetes之download api
download api作用: 可以通过环境变量或Volume挂载将pod信息注入到容器内部 apiVersion: apps/v1 kind: Deployment metadata: name: ...
- python基础:数据类型二
一.元组类型 二.字典类型 三.集合 一.元组类型 # 什么是元组: 元组就是一个不可变的列表 # ======================================基本使用======== ...
- 使用python2与python3创建一个简单的http服务(基于SimpleHTTPServer)
python2与python3基于SimpleHTTPServer创建一个http服务的方法是不同的: 一.在linux服务器上面检查一下自己的python版本:如: [root@zabbix ~]# ...
- Caffe---Pycaffe 绘制loss和accuracy曲线
Caffe---Pycaffe 绘制loss和accuracy曲线 <Caffe自带工具包---绘制loss和accuracy曲线>:可以看出使用caffe自带的工具包绘制loss曲线和a ...