2021-01-05汇编学习00
请注意,本文编写于 693 天前,最后修改于 204 天前,其中某些信息可能已经过时。

目录


一、构造函数

struct Person
{
	int age;
	int level;
    //构造函数
	Person()
	{
		printf("Person对象创建了\n");
	}
	//重载构造函数
	Person(int age,int level)
	{
		this->age = age;
		this->level = level;
	}
	void Print()
	{
		printf("%d-%d\n",age,level);
	}
};

构造函数的特点:

  1. 与类同名

  2. 没有返回值

  3. 创建对象的时候执行

  4. 主要用于初始化

  5. 可以有多个(最好有一个无参的),称为重载 其他函数也可以重载

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

二、析构函数

# include "stdafx.h"
# include "stdlib.h"
# include <windows.h>

struct Person
{
	int age;
	int level;
	char* arr;
	Person()
	{
		printf("无参构造函数执行了...");
	}
	Person(int age,int level)
	{
		printf("有参构造函数执行了...");
		this->age = age;
		this->level = level;
		arr = (char*)malloc(1024);
	}
	~Person()
	{
		printf("析构函数执行了...");
		free(arr);
		arr = NULL;
	}
	void Print()
	{
		printf("%d-%d\n",age,level);
	}
};


int main(int argc, char* argv[])
{
	return 0;
}

析构函数的特点:

  1. 只能有一个析构函数,不能重载

  2. 不能带任何参数

  3. 不能带返回值

  4. 主要用于清理工作

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

三、继承本质

1、观察反汇编

struct Person
{
	int age;
	int sex;
};
struct Teacher
{
	int age;
	int sex;
	int level;
	int classId;
};
struct Student
{
	int age;
	int sex;
	int code;
	int score;
};

Teacher t;				                观察反汇编:

t.age = 1;				                mov         dword ptr [ebp-10h],1
t.sex = 2;				                mov         dword ptr [ebp-0Ch],2
t.level = 3;				            mov         dword ptr [ebp-8],3
t.classId = 4;				            mov         dword ptr [ebp-4],4
				                        push        10h
printf("%d\n",sizeof(t));				push        offset string "%d\n" (0042201c)
				                        call        printf (004010e0)
				                        add         esp,8

Student s;				                mov         dword ptr [ebp-10h],1
				                        mov         dword ptr [ebp-0Ch],2
s.age = 1;				                mov         dword ptr [ebp-8],3
s.sex = 2;				                mov         dword ptr [ebp-4],4
s.code = 3;				                push        10h
s.score = 4;			                push        offset string "%d\n" (0042201c)
				                        call        printf (004010e0)
printf("%d\n",sizeof(s));				add         esp,8

2、改变写法:

struct Person
{
	int age;
	int sex;
};
struct Teacher:Person
{
	int level;
	int classId;
};
struct Student:Person
{
	int code;
	int score;
};
				        观察反汇编:

Teacher t;	                    mov         dword ptr [ebp-10h],1
                                mov         dword ptr [ebp-0Ch],2
t.age = 1;				        mov         dword ptr [ebp-8],3
t.sex = 2;				        mov         dword ptr [ebp-4],4
t.level = 3;				    push        10h
t.classId = 4;				    push        offset string "%d\n" (0042201c)
				                call        printf (004010e0)
printf("%d\n",sizeof(t));		add         esp,8


Student s;				        mov         dword ptr [ebp-10h],1
				                mov         dword ptr [ebp-0Ch],2
s.age = 1;				        mov         dword ptr [ebp-8],3
s.sex = 2;				        mov         dword ptr [ebp-4],4
s.code = 3;				        push        10h
s.score = 4;				    push        offset string "%d\n" (0042201c)
				                call        printf (004010e0)
printf("%d\n",sizeof(s));	    add         esp,8

总结

  1. 什么是继承?

继承就是数据的复制

  1. 为什么要用继承?

减少重复代码的编写

  1. Person 称为父类或者基类

  2. Teacher、Student称为子类或者派生类

  3. t和s可以称为对象或者实例.

  4. 可以用父类指针指向子类的对象.

四、多层继承

struct X
{				        mov         dword ptr [ebp-18h],1
	int a;			    mov         dword ptr [ebp-14h],2
	int b;			    mov         dword ptr [ebp-10h],3
};				        mov         dword ptr [ebp-0Ch],4
struct Y:X				mov         dword ptr [ebp-8],5
{				        mov         dword ptr [ebp-4],6
	int c;			    push        18h
	int d;			    push        offset string "%d\n" (0042201c)
};				        call        printf (004010e0)
struct Z:Y				add         esp,8
{
	int e;
	int f;
};

Z z;

z.a = 1;
z.b = 2;
z.c = 3;
z.d = 4;
z.e = 5;
z.f = 6;

printf("%d\n",sizeof(z));

struct X
{
	int a;
	int b;
};
struct Y:X
{
	int a;
	int d;
};
struct Z:Y
{
	int e;
	int f;
};

Z z;

z.X::a = 1;
z.b = 2;
z.Y::a = 3;
z.d = 4;
z.e = 5;
z.f = 6;

printf("%d\n",sizeof(z));
printf("%d\n",z.X::a);
printf("%d\n",z.b);
printf("%d\n",z.Y::a);
printf("%d\n",z.d);
printf("%d\n",z.e);
printf("%d\n",z.f);

五、多重继承

struct X
{
	int a;
	int b;
};
struct Y
{
	int c;
	int d;
};
struct Z:X,Y
{
	int e;
	int f;			        观察反汇编:
};

				            mov         dword ptr [ebp-18h],1
Z z;				        mov         dword ptr [ebp-14h],2
				            mov         dword ptr [ebp-10h],3
z.a = 1;				    mov         dword ptr [ebp-0Ch],4
z.b = 2;				    mov         dword ptr [ebp-8],5
z.c = 3;				    mov         dword ptr [ebp-4],6
z.d = 4;				    push        18h
z.e = 5;				    push        offset string "%d %x\n" (0042201c)
z.f = 6;				    call        printf (004010e0)
				            add         esp,8
printf("%d\n",sizeof(z));

总结:

一个子类可以有多个父类,即多重继承

继承的特性

struct X
{
int a;
int b;
};
struct Y
{
int a;
int d;
};
struct Z,Y
{
int e;
int f;
}; 观察反汇编:

Z z; mov dword ptr [ebp-18h],1
mov dword ptr [ebp-14h],2
z.X::a = 1; mov dword ptr [ebp-10h],3
z.b = 2; mov dword ptr [ebp-0Ch],4
z.Y::a = 3; mov dword ptr [ebp-8],5
z.d = 4; mov dword ptr [ebp-4],6
z.e = 5; push 18h
z.f = 6; push offset string "%d %x\n" (0042201c)
call printf (004010e0)
printf("%d\n",sizeof(z)); add esp,8
printf("%d\n",z.X::a);
printf("%d\n",z.b);
printf("%d\n",z.Y::a);
printf("%d\n",z.d);
printf("%d\n",z.e);
printf("%d\n",z.f);

总结:

  1. 多重继承增加了程序的复杂度,容易出错
  2. 微软建议使用单继承,如果需要多重继承可以改为多层继承

作业

1、设计一个结构 DateInfo,要求其满足下述要求。

(1) 有三个成员: int year; int month;int day;
(2) 要求有个带参数的构造函数,其参数分别为对应年、月、日。
(3) 有一个无参数的构造函数,其初始的年、月、日分别为:2015、4、2。
(4) 要求有一个成员函数实现日期的设置:SetDay(int day)
(5) 要求有一个成员函数实现日期的获取: GetDay()
(6) 要求有一个成员函数实现年份的设置: SetYear(int year)
(7) 要求有一个成员函数实现年份的获取: GetYear()
(8) 要求有一个成员函数实现月份的设置: SetMonth(int month)
(9) 要求有一个成员函数实现月份的获取: GetMonth()

2、设计一个结构 TimeInfo,要求其满足下述要求。

(1) 该结构中包含表示时间的时、分、秒。
(2) 设置该结构中时、分、秒的函数。
(3) 获取该结构中时、分、秒的三个函数:GetHour(),GetMinute()和GetSecond()。

3、让TimeInfo继承DateInfo 分别使用DataInfo和TimeInfo的指针访问TimeInfo对象的成员.

# include "stdafx.h"
# include "malloc.h"

struct DateInfo
{
	int year;
	int month;
	int day;
	//(1) 有三个成员: int year; int month;int day;
	//(2)要求有个带参数的构造函数,其参数分别为对应年、月、日。
	DateInfo(int year,int month,int day)
	{
		this->year = year;
		this->month = month;
		this->day = day;
	}
	//(3) 有一个无参数的构造函数,其初始的年、月、日分别为:2015、4、2
	DateInfo()
	{
		year = 2015;
		month = 4;
		day = 2;
	}
	//(4)要求有一个成员函数实现日期的设置:SetDay(int day)
	void SetDay(int day)
	{
		this->day = day;
	}
	//(5)要求有一个成员函数实现日期的获取: GetDay()
	void GetDay()
	{
		printf("日:%d\n",day);
	}
	//(6)要求有一个成员函数实现年份的设置: SetYear(int year)
	void SetYear(int year)
	{
		this->year = year;
	}
	//(7)要求有一个成员函数实现年份的获取: GetYear()
	void GetYear()
	{
		printf("年:%d\n",year);
	}
	//(8)要求有一个成员函数实现月份的设置: SetMonth(int month)
	void SetMonth(int month)
	{
		this->month = month;
	}
	//(9)要求有一个成员函数实现月份的获取: GetMonth()
	void GetMonth()
	{
		printf("月:%d\n",month);
	}
};

struct TimeInfo:DateInfo
{
	int Hour;
	int Minute;
	int Second;
	//(1)该结构中包含表示时间的时、分、秒

	TimeInfo(int Hour,int Minute,int Second)
	{
		this->Hour = Hour;
		this->Minute = Minute;
		this->Second = Second;
	}
	TimeInfo()
	{
		Hour = 15;
		Minute = 14;
		Second = 20;
	}
	//(2)设置该结构中时、分、秒的函数。
	void SetTime(int Hour,int Minute,int Second)
	{
		this->Hour = Hour;
		this->Minute = Minute;
		this->Second = Second;
	}
	void GetHour()
	{
		printf("时:%d\n",Hour);
	}
	void GetMinute()
	{
		printf("分:%d\n",Minute);
	}
	void GetSecond()
	{
		printf("秒:%d\n",Second);
	}

};

void Test()
{
	/*
	DateInfo d;
	d.SetYear(2019);
	d.SetMonth(9);
	d.SetDay(21);
	d.GetYear();
	d.GetMonth();
	d.GetDay();
	*/
	//Time
	TimeInfo t;
	t.SetYear(2020);
	t.SetMonth(9);
	t.SetDay(25);
	t.GetYear();
	t.GetMonth();
	t.GetDay();

	//让TimeInfo继承DateInfo 分别使用DataInfo和TimeInfo的指针访问TimeInfo对象的成员.

	t.SetTime(15,25,30);
	t.GetHour();
	t.GetMinute();
	t.GetSecond();

	//TimeInfo的指针访问TimeInfo
	printf("修改后!\n");
	TimeInfo* pt = &t;
	pt->SetTime(16,20,24);
	pt->GetHour();
	//DataInfo的指针访问TimeInfo
	DateInfo* pd = &t;
	pd->SetYear(2021);
	pd->GetYear();

}


int main(int argc, char* argv[])
{
	Test();
	return 0;
}

4、设计一个结构叫做MyString,要求该结构能够完成以下功能:

(1) 构造函数能够根据实际传入的参数分配实际存储空间;
(2) 提供一个无参的构造函数,默认分配大小为1024个字节;
(3) 析构函数释放该空间;
(4) 编写成员函数SetString,可以将一个字符串赋值给该结构;
(5) 编写成员函数PrintString,可以将该结构的内容打印到屏幕上;
(6) 编写成员函数AppendString,用于向已有的数据后面添加数据;
(7) 编写成员函数Size,用于得到当前数据的真实长度。
编写测试程序,测试这个结构。

# include "stdafx.h"
# include "stdio.h"
# include "string.h"
# include "malloc.h"
# include "memory.h"


struct MyString
{
	char* arr;
	int num;

	MyString(int num)
	{
		this->num = num;
		arr = (char*)malloc(this->num);
		if(arr == NULL)
		{
			printf("空间申请失败!\n");
		}
	memset(arr,0,num);
	}
	MyString()
	{
		arr = (char*)malloc(1024);
		if(arr == NULL)
		{
			printf("空间申请失败!\n");
		}
	memset(arr,0,1024);
	}
	~MyString()
	{
		printf("析构函数执行!\n");
		free(arr);
		arr = NULL;
		printf("内存已释放!\n");
	}

	void SetString(char* str)
	{
		strcpy((char*)arr,str);
	}

	void PrintString()
	{
		printf("字符串:%s\n",arr);
	}

	void AppendString(char* AddStr)
	{
		strcat((char*)arr,AddStr);
	}

	void Size()
	{
		printf("长度:%d\n",strlen(arr));
	}
};


void Test()
{
	MyString m;
	char str[] = "ayongga";
	m.SetString(str);
	m.PrintString();
	m.Size();
	char str2[] = "na1r";
	m.AppendString(str2);
	m.PrintString();
	m.Size();
}

int main(int argc, char* argv[])
{ 
	Test();
	return 0;
}

笔记来自滴水三期

本文作者:Na1r

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!