C++逆向分析——构造函数和析构函数

发布时间 2023-04-09 10:49:28作者: bonelee

构造函数与析构函数

构造函数

struct Student {
int a;
int b;
 
Student() {
printf("Look.");
}
 
void Init(int a, int b) {
this->a = a;
this->b = b;
}
 
};

如上代码中,我们发现了存在一个函数,这个函数没有返回类型并且与结构体名称一样,那这段函数在什么时候执行呢?

我们先不使用之前学习的方法去调用,直接创建一个对象,这时候会发现该函数就直接执行了:

images/download/attachments/12714553/image2021-3-31_17-4-32.png

这个函数,我们就称之为构造函数。

它的汇编代码如下:

images/download/attachments/12714553/image2021-3-31_17-30-51.png

如果我们想要在创建对象的时候,自定义初始化成员的值,就可以在析构函数上加上参数:

struct Student {
int a;
int b;
 
Student(int a, int b) {
this->a = a;
this->b = b;
}
 
void Init(int a, int b) {
this->a = a;
this->b = b;
}
 
};
 
void main() {
Student s(1, 2);
 
return;
}

创建对象的时候,在对象名后面加上括号传入即可;但是这样就会存在一个问题,我们不想初始化值的时候就没有办法创建这个类:

struct Student {
int a;
int b;
 
Student(int a, int b) {
this->a = a;
this->b = b;
}
 
void Init(int a, int b) {
this->a = a;
this->b = b;
}
 
};
 
void main() {
Student s;
 
return;
}

编译直接出错:

images/download/attachments/12714553/image2021-4-1_15-42-56.png

这是因为编译器发现你没有传入参数,就会去寻找没有参数的构造函数,但是在这段代码中没有声明,所以需要声明一下:

#include <stdio.h>
struct Student {
int a;
int b;
 
Student() {
printf("Look.");
}
 
Student(int a, int b) {
this->a = a;
this->b = b;
}
 
void Init(int a, int b) {
this->a = a;
this->b = b;
}
 
};
 
void main() {
Student s;
 
return;
}

这样就没有任何问题了,你想传参就传,不想就不传。

我们总结一下其(构造函数)特点

  1. 构造函数名称与类名一样

  2. 不能写返回类型(无返回值)

  3. 创建对象时,则会自动调用执行,一般用于初始化

  4. 可以有多个构造函数(建议只有一个无参的),这种声明方式我们称之为重载(其他函数也可以)

  5. 编译器不要求必须提供构造函数

析构函数

析构函数函数的语法跟构造函数很像,其区别就是:析构函数需要在函数名前面加一个波浪号析构函数只能有一个析构函数函数不可以写参数构造函数是创建对象的时候执行,但是析构函数函数是在对象销毁前执行

#include <stdio.h>
struct Student {
int a;
int b;
 
Student() {
printf("Look.");
}
 
Student(int a, int b) {
this->a = a;
this->b = b;
}
 
~Student() {
printf("Look A.");
}
 
void Init(int a, int b) {
this->a = a;
this->b = b;
}
 
};
 
void main() {
Student s;
 
return;
}

析构函数函数是在对象销毁前执行,那么对象会在什么时候销毁呢?可以看下反汇编代码:

images/download/attachments/12714553/image2021-4-1_16-9-20.png

会发现在程序执行结束,也就是main函数的return之后会执行析构函数函数,但这句话实际上是不严谨的,因为我们的main函数是没有返回值的,也就是return不会有对应的汇编代码,当我们设置返回值再来看下反汇编代码:

#include <stdio.h>
struct Student {
int a;
int b;
 
Student() {
printf("Look.");
}
 
Student(int a, int b) {
this->a = a;
this->b = b;
}
 
~Student() {
printf("Look A.");
}
 
void Init(int a, int b) {
this->a = a;
this->b = b;
}
 
};
 
int main() {
Student s;
 
return 0;
}

images/download/attachments/12714553/image2021-4-1_16-12-49.png

可以很清晰的看见,析构函数是在return返回之前执行的。

我们总结(析构函数)一下:

  1. 只能有一个,不支持重载

  2. 无返回值

  3. 无任何参数

  4. 主要用于清理工作

  5. 编译器不要求必须提供

  6. 当对象在main函数(堆栈)中创建,在return之前调用执行;当对象在全局变量区,则会在应用程序退出之前调用