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. 复制Linux虚拟机(VMware vSphere Client 工具)

    1.VMware vSphere Client 工具 登录,如下图          IP.用户名/密码均是物理机,登录完成界面: 2.选择一个复制的原虚拟机 A,点击左上角[文件]——导出——导出O ...

  2. 给自己看的Cache,三段代码

    此篇是我记录代码的一个草稿,不是一篇正式的博文,误点的别介意啊. 公司的框架中Cache实现文件: (1)CacheUtil.cs using System.Collections.Generic; ...

  3. 使用HttpClient调用接口

    一,编写返回对象 public class HttpResult { // 响应的状态码 private int code; // 响应的响应体 private String body;get/set ...

  4. Java自学-数组 增强型for循环

    Java 中如何使用增强for循环 增强型for循环在遍历一个数组的时候会更加快捷 步骤 1 : 增强型for循环 注:增强型for循环只能用来取值,却不能用来修改数组里的值 public class ...

  5. Oracle PLSQL数据导出csv的案例

    之前项目运维人员碰到一个问题,需要写一个存储过程,把数据导出为csv文件,查了一些资料,帮他写成了一个PLSQL,今天拿出来分享一下,不足之处,欢迎指教. 数据背景:  用到两张表,一张存放单位组织名 ...

  6. Python人工智能第二篇:人脸检测和图像识别

    Python人工智能第二篇:人脸检测和图像识别 人脸检测 详细内容请看技术文档:https://ai.baidu.com/docs#/Face-Python-SDK/top from aip impo ...

  7. 英语affrike非洲

    中文名称:阿非利加洲(全称) 外文名称:Africa 别 名:Affrike 行政区类别洲 下辖地区北非.东非.西非.中非.南非 地理位置:东濒印度洋,西临大西洋,北至地中海,南至好望角 面 积:30 ...

  8. Oracle 11g RAC to RAC ADG搭建(一)采用rman备份恢复方式

    (一)基础环境   主库 备库 操作系统 RedHat6.7 RedHat6.7 服务器名称 primarydb1primarydb2 standbydb1standbydb2 IP地址规划 192. ...

  9. minikube国内在线部署体验

    问题描述: 快速学习k8s的各个组件的作用及yml的编写,minikube很适合. how to install Minikube, a tool that runs a single-node Ku ...

  10. shell输出文本颜色

    绿地白字 echo -e "\033[42;37m 绿底白字 \033[0m"