滴水逆向笔记系列-c++总结1-34.this指针-35.继承_构造_析构函数

第三十四课 c++1 this指针

海哥的一句话:学c++就是学编译器帮我们做了多少事情

1.结构体参数传递

结构体直接作为函数参数传递时,本质上是将结构体成员copy一份传到函数的栈中,这样会比较浪费空间。所以一般我们使用结构体指针传参

struct Base{
    int x;
    int y;
	/*int Max(Base* pb){  //结构体指针传参
    	return pb->x + pb->y;
	}*/
};
int Max(Base* pb){  //结构体指针传参
    return pb->x + pb->y;
}
int main(int argc,char* argv[]){
    Base base;
    base.x = 1;
    base.y = 2;
  	printf("%d\n",Max(&base));
    printf("%d",sizeof(base));  //打印一下结构体的大小
    return 0;
}

函数放在结构体内和结构体外时,我们可以看到打印出来的结构体大小都是8;但是调用的时候就需要使用base.Max()去调用

总结:

  • 函数在结构体内外从底层来看是没有区别的,都是直接找到函数地址就可以调用,但是从编译器角度来看,为了方便管理,所以需要用base.Max()去调用
  • 而且函数就算放在结构体里面,但函数地址也不在结构体里面

封装:

  • 把函数扔到结构体里面了就是封装,
  • 为什么扔到结构体里面?因为使用里面的变量方便,因为创建函数的时候会替我们自动传递结构体的首地址
  • 可以把结构体看作就是一个类,那么用这个结构体(类)创建的就是对象
  • 结构体里的变量,函数都叫成员

2.this指针

this就是上面所说的成员函数会被自动多传一个结构体首地址,这个就是this指针
用下来感觉最大的用处就是区分函数和类里重复名的变量,this->day就是类里的,day就是函数里的局部函数

0x01 this指针的用处

用处一:初始化函数内区分传参与成员变量

在下面代码中,在Max()函数里感觉有没有this好像都可以编译运行,不需要this也没问题
但是在init初始化函数里,没有使用this就会出问题了,编译器并不知道哪个是传参进来的xy,哪个是base结构体里的成员变量xy
image.png
所以使用this指针即可分别处理
image.png

用处二:返回当前对象的首地址

image.png

0x02 this使用注意

  • 编译器不允许我们对this指针重新赋值

image.png
因为this指针在c++里面是个关键词,编译器认为他只需要代表结构体首地址即可,不需要去进行运算

作业

image.png
1、

#include <stdio.h>
struct xy
{
	/*int x = 1;
	int y = 2;

	int add()
	{
		return x + y;
	}
	int decrease()
	{
		return x - y;
	}
	int ride()
	{
		return x * y;
	}
	int divide()
	{
		return x / y;
	}*/
};
int a = 3;
int b = 4;
int add()
{
	return a + b;
}

int main() {
	xy xy;
	//xy.add();
	printf("size: %d",sizeof(xy));
	add();
}

2、成员函数多传了一个this(结构体首地址)给ecx寄存器
image.pngimage.png
3、空结构体大小
image.png
image.png
4、
image.png

image.png
无法执行

第三十五课 c++2 继承 构造-析构函数

1.重载

函数包括构造函数都可以存在多个一样的函数,这种就叫重载
只要传参个数或者类型不一样即可,根据你的传参个数或者类型判断你使用的是哪个函数
析构函数不能重载

2.继承

  • 使用继承和没使用继承自己创建变量的汇编语句是一样的,没有区别
  • 相当于编译器替我们复制了这些重复的成员变量而已

image.png
image.png

总结:

1、什么是继承?
继承就是数据的复制
2、为什么要用继承?
减少重复代码的编写
3、Person 称为父类或者基类
4、Teacher、Student称为子类或者派生类
5、t和s可以称为对象或者实例.
6、可以用父类指针指向子类的对象,但是最好不要用子类指针指向父类对象。

可以使用子类指针去访问,也可以用父类的指针访问,甚至不用转换类型
image.pngimage.png
相当于编译器帮忙把父类的成员变量赋值到子类对象里面
image.png
但是Person* pt = &t不能pt->a或者pt->b父类指针访问子类的成员变量
子类指针访问父类成员变量编译器是不允许的,但是底层来说只要把类型强转一下骗过编译器即可执行,
image.png
但一般不建议这么执行,因为父类只有两个变量的空间,但是使用子类指针时,我们指向了四个变量的空间,很容易访问越界,访问出奇怪的东西,后面调试很麻烦
image.png

3.多层继承

正常情况

爷爷的东西也都可以继承过来,编译器帮忙复制到子类的空间里
image.png

父类与子类重名的情况(还有一种情况看多态笔记的两个例子)

可以看到大小照样还是24,只不过编译器在赋值的时候自己会乱,不知道你要赋值哪个,所以需要z.X::a去赋值
而且在反汇编中和上面还是一样的,在底层没有区别,重名的变量名字只是给程序员自己看的,底层不管你重不重名
image.png

4.多重继承

image.png

5.子类的构造函数自动调用父类构造函数

image.png
反汇编看看怎么回事
在创建对象时,sub自动调用了自己的构造函数(即使我们没写构造函数)
image.png
跟进sub构造函数后发现里面就调用了父类的构造函数
image.png
跟进Base的构造函数
image.png

作业image.png

image.png
image.png
image.png

#pragma warning(disable:4996)
#include <stdio.h>
#include <windows.h>
struct DateInfo
{
	int year;
	int month;
	int day;
	DateInfo(int year , int month , int day)
	{

	}
	DateInfo()
	{
		year = 2015;
		month = 4;
		day = 2;
	}
	void SetDay(int day)
	{
		this->day = day;
	}
	int GetDay()
	{
		return this->day;
	}
	void SetYear(int year)
	{
		this->year = year;
	}
	int GetYear()
	{
		return this->year;
	}
	void SetMonth(int month)
	{
		this->month = month;
	}
	int GetMonth()
	{
		return this->month;
	}

};
struct TimeInfo:DateInfo
{
	int Hour;
	int Minute;
	int Second;
	void SetHour(int Hour)
	{
		this->Hour = Hour;
	}
	int GetHour()
	{
		return this->Hour;
	}
	void SetMinute(int Minute)
	{
		this->Minute = Minute;
	}
	int GetMinute()
	{
		return this->Minute;
	}
	void SetSecond(int Second)
	{
		this->Second = Second;
	}
	int GetSecond()
	{
		return this->Second;
	}
};
struct MyString
{
	PVOID addr;
	char* str;
	int size;
	MyString()
	{
		str = (char*)malloc(1024);
		printf("构造函数执行成功\n");
	}
	void mallocstr()
	{
		str = (char*)malloc(size);
	}
	~MyString()
	{
		free(str);
	}
	void SetString(char* str)
	{
		strcpy(this->str, str);
	}
	void PrintString()
	{
		printf("string:%s\nsize:%d", str,size);
	}
	void Size()
	{
		this->size = strlen(str);
	}
};

int main(int argc, char* argv[])
{
	/*TimeInfo time;
	DateInfo* pd = & time;
	printf("父类指针访问子类对象:%d\n", pd->day);
	time.SetHour(6);
	TimeInfo* pt = &time;
	printf("子类指针访问子类对象:%d\n",pt->Hour);*/
	MyString ms;
 	const char* string = "abcde";
	ms.SetString((char*)string);
	ms.Size();
	ms.PrintString();
}

注意:
1、这样子赋值是错误的,并不是赋值而是创建了新的局部变量
image.pngimage.png
2、
image.pngimage.png
3、打印字符串的大小应该使用strlen
image.pngimage.png

posted @ 2024-03-16 10:42  小新07  阅读(18)  评论(0编辑  收藏  举报