class TestClass
{
public:
void setNum(int num)
{
m_num1 = num;
}
int getNum()
{
return m_num1;
}
private:
int m_num1;
int m_num2;
};
#include "pch.h"
#include <iostream>
#include "mytest.h" int main()
{
TestClass test;
test.setNum(); printf("sizeof testClass=%d,num = %d\n", sizeof(test), test.getNum()); std::cout << "Hello World!\n";
}

输出:sizeof testClass=8,num = 100

没有虚函数时,test变量在内存中的分布

若存在虚函数

class TestClass
{
public:
virtual void setNum(int num)
{
m_num1 = num;
}
virtual int getNum()
{
return m_num1;
}
private:
int m_num1;
int m_num2;
};

我们用IDA打开看一下反汇编

ext:004127B0 var_D8          = byte ptr -0D8h
.text:004127B0 var_14 = byte ptr -14h
.text:004127B0 var_4 = dword ptr -
.text:004127B0
.text:004127B0 push ebp
.text:004127B1 mov ebp, esp
.text:004127B3 sub esp, 0D8h
.text:004127B9 push ebx
.text:004127BA push esi
.text:004127BB push edi
.text:004127BC lea edi, [ebp+var_D8]
.text:004127C2 mov ecx, 36h
.text:004127C7 mov eax, 0CCCCCCCCh
.text:004127CC rep stosd
.text:004127CE mov eax, ___security_cookie
.text:004127D3 xor eax, ebp
.text:004127D5 mov [ebp+var_4], eax
.text:004127D8 mov ecx, offset unk_41E009
.text:004127DD call sub_411299
.text:004127E2 lea ecx, [ebp+var_14] // ecx 保存this指针,通过this指针地址偏移来调用类成员
.text:004127E5 call sub_411311
.text:004127EA push
.text:004127EC lea ecx, [ebp+var_14]
.text:004127EF call sub_41113B
.text:004127F4 lea ecx, [ebp+var_14]
.text:004127F7 call sub_4112A8
.text:004127FC push eax
.text:004127FD push 0Ch
.text:004127FF push offset aSizeofTestclas ; "sizeof testClass=%d,num = %d\n"
.text: call sub_411055
.text: add esp, 0Ch
.text:0041280C push offset Str ; "Hello World!\n"
.text: mov eax, ds:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::basic_ostream<char,std::char_traits<char>> std::cout
.text: push eax ; int
.text: call sub_411226

对象作为返回值
1、分配一个临时对象空间 main_object;
2、把临时对象入栈
3、调用返回局部对象的函数

在返回局部对象的函数里面
fun_object;
一些局部变量操作
返回的时候用用局部对象作为参数,传入main_object对象的this指针
调用复制构造函数
用EAX返回this指针

tt=main_object;

一下转自:https://blog.csdn.net/qq_22660775/article/details/89854545

C++规定当函数返回的是非引用类型时,函数会创建临时对象(temporary object),函数返回的就是这个临时对象。在求解表达式时,如果需要一个地方存储其运算结果,编译器会创建一个没有命名的对象,这就是临时对象。浅显的说,当你调用了函数,函数会 return一个值 那么这个值总得有存放的地方吧,编译器就把会把值存放在一个没有命名法临时对象中。

我们举个例子来说明一下,首先定义一个类:

class B {
public:
B(){
cout << "B的构造函数" << endl;
} B(int i){
cout << "带int型参数的B的构造函数" << endl;
} B(const B &ano){
cout << "B的复制构造函数" << endl;
} B& operator=(const B& rhs){
cout << "B的赋值操作符" << endl;
return *this;
} virtual ~B(){
cout << "B的析构函数" << endl;
}
};

定义一个函数:

B func2()
{
B b;
return b;
}

上面的函数返回一个非引用类型的变量,我们写两个测试函数,来看看返回一个非引用类型的变量会发生什么

void test1() {
B t;
t = func2();
} void test2() {
B t = func2();
}

运行测试函数test1(),其运行结果为:

B的构造函数 //构造主方法内的对象t
B的构造函数 //构造fun2内的局部对象b
B的复制构造函数 //将func2的局部对象复制到一个临时对象
B的析构函数 //析构局部对象b
B的赋值操作符 //使用临时对象初始化t
B的析构函数 //析构临时对象
B的析构函数 //析构对象t

由于 t 的初始化采用的是operator=操作符,operator=要求必须使用一个已经创建好了的对象对左值进行复制,所以此时必须先形成一个临时对象,然后将临时对象赋值给 t

运行测试函数test2(),其运行结果为:

B的构造函数 //构造fun2内的局部对象b
B的复制构造函数
B的析构函数
B的析构函数

由于 t 是通过复制构造函数进行初始化的。复制构造函数初始化要求左值是一个已有对象,而非创建好了的对象,因此此时不需要创建一个临时对象

C++对象内存布局,this指针,对象作为参数,作为返回值的更多相关文章

  1. c++ 指针做为参数和返回值

    指针参数 返回值是指针 一.指针作参数形式的函数 //计算x的平方 x*x void square(int *x) { int a=*x; *x=a*a; } 二.指针作返回值的函数 int *squ ...

  2. Java对象内存布局

    本文转载自Java对象内存布局 导语 首先直接抛出问题 Unsafe.getInt(obj, fieldOffset)中的fieldOffset是什么, 类似还有compareAndSwapX(obj ...

  3. JVM-对象及对象内存布局

    目录 前言 类与对象 对象类二分模型 对象 对象内存布局 JOL工具 对象头 Mark Word 类型句柄 对象头与锁膨胀 无锁 偏向锁 轻量级锁 重量级锁 重量级锁降级 实例数据 填充 对象生命周期 ...

  4. 图说C++对象模型:对象内存布局详解

    0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局.虚表指针.虚基类指针等有深入了解的朋友可以慢慢看. 本文的结论都在VS2013上得到验证.不同的编译器在内存布局的细节上可能有 ...

  5. c++ 对象内存布局详解

    今天看了的,感觉需要了解对象内存的问题.参考:http://blog.jobbole.com/101583/ 1.何为C++对象模型? 引用<深度探索C++对象模型>这本书中的话: 有两个 ...

  6. c++对象内存布局

    这篇文章我要简单地讲解下c++对象的内存布局,虽然已经有很多很好的文章,不过通过实现发现有些地方不同的编译器还是会有差别的,希望和大家交流. 在没有用到虚函数的时候,C++的对象内存布局和c语言的st ...

  7. 从C++对象内存布局和构造过程来具体分析C++中的封装、继承、多态

    一.封装模型的内存布局 常见类对象的成员可能包含以下元素: 内建类型.指针.引用.组合对象.虚函数. 另一个角度的分类: 数据成员:静态.非静态 成员函数:静态.非静态.虚函数 1.仅包含内建类型的场 ...

  8. c++对象内存布局的理解

    我对c++对象内存布局的理解   引言 结合网上的一些资料,通过自己的一番摸索,得出了一点个人见解.现在写下来,希望与各位同学共同探讨,共同进步. 以下所有代码均是在VS2012下测试. 一个普通的基 ...

  9. 好文章系列C/C++——图说C++对象模型:对象内存布局详解

    注:收藏好文章,得出自己的笔记,以查漏补缺!     ------>原文链接:http://blog.jobbole.com/101583/ 前言 本文可加深对C++对象的内存布局.虚表指针.虚 ...

  10. 使用sos查看.NET对象内存布局

    前面我们图解了.NET里各种对象的内存布局,我们再来从调试器和clr源码的角度来看一下对象的内存布局.我写了一个测试程序来加深对.net对象内存布局的了解: using System; using S ...

随机推荐

  1. Golang 传递任意类型的切片

    肯定有这样的一种场景,写一个函数,该函数可以接收任意类型的切片,完成相应的功能. 就好比这种情况 intSlice := []int{1,2,3,4,5,6,7,8} strSlice := []st ...

  2. VC++如何利用Matlab2014b的图形引擎进行绘图

    VC++如何利用Matlab的图形引擎 在Visual C++ 2015 工程中使用 Matlab2014b 提供的图形引擎进行绘图的详细过程. 问题来源: 有时候用C++写一些演示程序,有数据可视化 ...

  3. Parameter 0 of method sqlSessionTemplate in org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration required a single bean, but 2 were found:

    Parameter 0 of method orderSqlSessionFactory in com.config.MultipleDBConfig required a single bean, ...

  4. P2801 教主的魔法 (线段树)

    题目 P2801 教主的魔法 解析 成天做水题 线段树,第一问区间加很简单 第二问可以维护一个区间最大值和一个区间最小值,若C小于等于区间最小值,就加上区间长度,若C大于区间最大值,就加0 ps:求教 ...

  5. React Native 开发豆瓣评分(七)首页组件开发

    首页内容拆分 看效果图,首页由热门影院.豆瓣热门.热门影视等列表组成,每个列表又由头加横向滑动的 电影海报列表构成. 所以可以先把页面的电影海报.评分.列表头做成组件,然后在使用 ScrollView ...

  6. JavaWeb 之 Listener:监听器

    一.概述 1.事件监听机制 事件:        一件事情 事件源:    事件发生的地方 监听器:    一个对象 注册监听: 将事件.事件源.监听器绑定在一起. 2.监听器概念 当事件源上发生某个 ...

  7. SpringBoot 传入JSON对象参数

    1.请求参数格式必须是正确的JSON. 2.在入参中使用注解@RequestBody,用于接收JSON参数,使其自动转对象 3.关于lombok在此产生的一点小坑,@Builder对@RequestB ...

  8. Vue+Django项目部署

    本地项目配置 1 复制 luffy/settings/dev.py为prop.py 修改luffy/settings/prop.py中以下几项 (1) allow_hosts ALLOWED_HOST ...

  9. 【RocketMQ异常】Caused by: com.aliyun.openservices.shade.com.alibaba.rocketmq.client.exception.MQClientException: No route info of this topic, message-service-topic-testf

    一.异常信息 -- ::-thread-] ERROR c.x.x.r.service.producer.ali.AliMQProducerProcess.sendMessageFromQueue(A ...

  10. 五、Linux_ping命令

    ping命令用法为:“ping 参数 目标主机”.其中参数为零到多个,目标主机可以是IP或者域名. 1.每隔0.6秒ping一次,一共ping 5次: [root@aiezu.com ~]# ping ...