当前位置: 首页 > article >正文

汇编分析C++class

文章目录

  • this指针不神奇
    • 静态成员方法
  • 构造函数
    • 拷贝构造和移动构造
  • 运算符重载
    • 拷贝赋值和移动赋值
  • 多态机制
    • 虚函数
      • 虚表
        • 对象怎么获取虚表
    • 构造函数禁止为虚函数
    • 继承体系中析构函数必为虚函数
  • 模板对CPU不可见
  • malloc和new
    • free和delete
    • 请配对new和delete
      • free如何确定释放空间的大小

this指针不神奇

我们都知道面向对象是C++和C最大的区别,C++通过类将一组属性和一组方法捆绑在一起,分别称为成员属性和成员方法。对于非静态成员方法的访问必须通过实例化对象才能访问,对于非静态成员方法来说一般都会去读写特定的对象属性,因此如何确定读写哪个对象的属性就显得尤为重要了,这个问题通过this指针来解决,所谓this指针就是一个实例化对象的地址,编译器在编译时会自动的向调用非静态成员方法的地方添加一个隐含参数,这个参数就是this,方法内通过this寻址就可以确定目标读写对象

所谓的成员方法只是语法层面的说法,在汇编层面来说本质都是普通的函数

C++代码

class A{
public:
    void class_fun(){} //形式上无参,实则有一个参数
};
void normal_fun(long a){

}
int main(){
    A a;
    a.class_fun();
    normal_fun((long)&a);
    return 0;
}

汇编代码

A::class_fun():
;...
  mov QWORD PTR [rbp-8], rdi
;...
normal_fun(long):
;...
  mov QWORD PTR [rbp-8], rdi
;...
main:
;...
  lea rax, [rbp-1]
  mov rdi, rax
  call A::class_fun()
  
  lea rax, [rbp-1]
  mov rdi, rax
  call normal_fun(long)
;...

通过汇编结果可以很容易看出对于normal_funclass_fun的调用都由寄存器rdi保存参数,进入函数体后从中读取参数;通过对比normal_fun可以判断class_fun的的确确是有一个参数的,这个参数就是this

静态成员方法

根据上述结果不难知道为什么静态成员方法不能访问非静态成员属性了,因为对于静态成员方法来说它没有隐藏的this指针,自然就不知道读写哪一个对象的属性了,但是却可以读写静态成员属性(因为静态成员属性属于类而非对象)

C++代码

class A{
public:
    static void static_fun(){}
};

int main(){
    A::static_fun();
    return 0;
}

汇编代码

A::static_fun():
  push rbp
  mov rbp, rsp
  nop
  pop rbp
  ret
main:
  push rbp
  mov rbp, rsp
  call A::static_fun()
  mov eax, 0
  pop rbp
  ret

从汇编结果分析你看不到任何传参操作,即编译器不会为静态成员方法设置this指针

构造函数

构造函数也与普通函数一样,它也具有隐含的参数this,并且它是一个void返回类型的函数(void不需要显式声明)

C++ code

class A{
public: A(){x=1;}
protected: int x;
};
class B:public A{
public: B(){y=1;}
protected: int y;
};
int main(){
    A a;B b;
    return 0;
}

assembly code

A::A() [base object constructor]:
;...
  mov QWORD PTR [rbp-8], rdi ;读取this
  mov rax, QWORD PTR [rbp-8]
  mov DWORD PTR [rax], 1
;...
B::B() [base object constructor]:
;...
  mov QWORD PTR [rbp-8], rdi ;读取this
  mov rax, QWORD PTR [rbp-8]
  mov rdi, rax
  call A::A() [base object constructor]
  mov rax, QWORD PTR [rbp-8]
  mov DWORD PTR [rax+4], 1
;...

通过汇编可以看出派生类在构造函数中会先隐式调用基类的构造函数(对于汇编结果的line10~~line12),而后在执行派生类自己的构造函数,但是大多数情况下需要程序员在派生类的执行构造函数之前显


http://www.kler.cn/a/393000.html

相关文章:

  • html + css 淘宝网实战
  • 01 - 初识 Spring
  • OVS简介
  • 论文解读——掌纹生成网络 RPG-Palm升级版PCE-Palm
  • C++--------------树
  • 如何使用MySQL WorkBench操作MySQL数据库
  • 【征稿倒计时!华南理工大学主办 | IEEE出版 | EI检索稳定】2024智能机器人与自动控制国际学术会议 (IRAC 2024)
  • LabVIEW大数据处理
  • 网络学习第四篇
  • matlab建模入门指导
  • 【C++】用红黑树封装set和map
  • 【C语言刷力扣】58.最后一个单词的长度
  • 机器学习小补充(加深理解)
  • Matplotlib库中show()函数的用法
  • uniapp内把视频mp4的base64保持到手机文件系统
  • 基于STM32单片机多路无线射频抢答器
  • 算法笔记/USACO Guide GOLD金组Graphs并查集Disjoint Set Union
  • dolphinscheduler
  • Rust编写的贪吃蛇小游戏源代码解读
  • docker pull 网络不通
  • 01.Linux网络设置、FTP
  • 数据驱动的智能决策:民锋科技的量化分析方案
  • golang项目三层依赖架构,自底向上;依赖注入trpc\grpc
  • ES6进阶知识一
  • 【启程Golang之旅】一站式理解Go语言中的gRPC
  • 无人机反制技术与方法:主动防御,被动防御技术原理详解