C++ 底层分析 2.构造-析构,继承

构造函数(初始)

  • 与类同名
  • 没有返回值
  • 创建对象的时候执行
  • 主要用于初始化
  • 可以有好多个(最好有一个无参)
  • 编译器不要求必须提供

重载:函数名字一样 参数个数或者类型不一样

析构函数(清理)

  • 只能有一个析构函数,不能重载
  • 不能带任何参数
  • 不能带返回值
  • 主要用于清理工作
  • 编译器不要求必须提供

如下为析构函数和构造函数例子

struct Person 
{
   int age;
   int level;
   char* arr; 
   //构造函数
   Person(int age,int level)
   {
   		this->age = age;
   		this->level = level;
   		arr = (char*)malloc(1024);
   }
   //重载构造函数
   Person()
   {

   } 
   //析构函数
   ~Person()
   {

   		printf("析构函数执行了");
   		free(arr);
   		arr = NULL;
   }
   //成员函数
   void Print()
   {
   		printf("%d %d\n",age,level);
   }
   void Print(int x)
   {
   		printf("%d %d\n",age,level);
   }
};


int main()
{
   Person p(1,2);
   return 0;
}

继承

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				

变量是给编译器看的,对于底层来说,你取什么名字并没有什么意义
总结:

  • 什么是继承?继承就是数据的复制
  • 为什么要用继承?减少重复代码的编写
  • Person 称为父类或者基类
  • Teacher、Student称为子类或者派生类
  • t和s可以称为对象或者实例.
  • 可以用父类指针指向子类的对象.

图解:父类指针指向子类的对象.
C++ 底层分析 2.构造-析构,继承
2.多层继承

多层继承:				观察反汇编:				
								
struct X								
{									
	int a;								
	int b;								
};										
struct Y:X							
{										
	int c;							
	int d;								
};										
struct Z:Y								
{								
	int e;							
	int f;							
};								
								
								
Z z;								
								
z.a = 1;					mov         dword ptr [ebp-18h],1					
z.b = 2;					mov         dword ptr [ebp-14h],2				
z.c = 3;					mov         dword ptr [ebp-10h],3				
z.d = 4;					mov         dword ptr [ebp-0Ch],4				
z.e = 5;					mov         dword ptr [ebp-8],5					
z.f = 6;					mov         dword ptr [ebp-4],6				
							push        18h			
printf("%d\n",sizeof(z));	push        offset string "%d\n" (0042201c)								
							call        printf (004010e0)		
							add         esp,8		
								
														
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;					mov         dword ptr [ebp-18h],1				
z.b = 2;					mov         dword ptr [ebp-14h],2				
z.Y::a = 3;					mov         dword ptr [ebp-10h],3				
z.d = 4;					mov         dword ptr [ebp-0Ch],4				
z.e = 5;					mov         dword ptr [ebp-8],5				
z.f = 6;					mov         dword ptr [ebp-4],6				
							push        18h				
							push        offset string "%d\n"(0042201c)				
							call        printf (004010e0)				
							add         esp,8							
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);								

变量是给编译器看的,对于底层来说,你取什么名字并没有什么意义
有重名的成员,用::声明它属于哪个父类即可

3.多重继承

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

通过实验可以得出:一个子类可以有多个父类,即多重继承

对于重名的成员处理如上:

struct X									
{									
	int a;								
	int b;								
};									
struct Y									
{									
	int a;								
	int d;								
};									
struct Z:X,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);				

内存示意图如下:
C++ 底层分析 2.构造-析构,继承
总结:

  1. 多重继承增加了程序的复杂度,容易出错
  2. 微软建议使用单继承,如果需要多重继承可以改为多层继承
  3. [ebp-4]为最后一个赋值
  4. TimeInfo timeinfo;若有继承,则先执行子构造函数再执行父构造函数
#include<cmath>
#include<iostream>
#include<iomanip>
using namespace std;

struct DateInfo
{
   int year;
   int month;
   int day;
   DateInfo(int year,int month,int day)
   {
   	this->year = year;
   	this->month = month;
   	this->day = day;
   	cout<<"父类构造函数"<<endl;
   }
   DateInfo()
   {
   	this->year = 2015;
   	this->month = 4;
   	this->day = 2;
   	cout<<"父类构造函数"<<endl;
   }
   void SetDay(int day)
   {
   	this->day = day;
   }
   int GetDay()
   {
   	return this->day;
   }
   void SetMonth(int month)
   {
   	this->month = month;
   }
   int GetMonth()
   {
   	return this->month;
   }
   void SetYear(int year)
   {
   	this->year = year;
   }
   int GetYear()
   {
   	return this->year;
   }
};

struct TimeInfo:DateInfo
{
   int hour;
   int minute;
   int second;
   TimeInfo()
   {
   	this->hour = 12;
   	this->minute = 14;
   	this->second = 0;
   	cout<<"子类的构造函数"<<endl;
   }
   void SetHour()
   {
   	this->hour = hour;
   }
   void SetMinute()
   {
   	this->hour = hour;
   }
   void SetSecond()
   {
   	this->second = second;
   }
   int GetHour()
   {
   	return this->hour;
   }
   int GetMinute()
   {
   	return this->minute;
   }
   int GetSecond()
   {
   	return this->second;
   }
};


void Test()
{
   TimeInfo timeinfo;

   DateInfo* p = &timeinfo;
   p++;
   
   printf("%d",p->month);
}

int main()
{
   Test();

   return 0;
}

题目:
C++ 底层分析 2.构造-析构,继承

#include<cmath>
#include<iostream>
#include<iomanip>
using namespace std;
struct MyString
{
	char* arr;
	MyString(int Size)
	{
		this->arr = (char*)malloc(Size);
		memset(arr,0,Size);
	}
	MyString()
	{
		this->arr = (char*)malloc(1024);
		memset(arr,0,1024);
	}
	~MyString()
	{
		free(arr);
		arr = NULL;
	}
	void SetString(char* str1)
	{
		memcpy(arr,str1,strlen(str1));		
	}
	void PrintString()
	{
		printf("%s\n",arr);
	}
	void AppendString(char* stradd)
	{
		char* pTemparr = this->arr;
		while(*++pTemparr);
		memcpy(pTemparr,stradd,strlen(stradd));
	}
	int Size()
	{
		return strlen(arr);
	}

};

void Test1()
{
	MyString mystring(1000);
	mystring.SetString("哎Mikasys");
	mystring.PrintString();
	printf("%d\n",mystring.Size());
	mystring.AppendString("爱你爱你");
	mystring.PrintString();
	printf("%d\n",mystring.Size());
}
int main()
{
	Test1();
	
	return 0;
}
上一篇:《C++反汇编与逆向分析技术揭秘》--钱林松,赵海旭 著


下一篇:你不知道的JavaScript(五)内置对象模版