构造函数(初始)
- 与类同名
- 没有返回值
- 创建对象的时候执行
- 主要用于初始化
- 可以有好多个(最好有一个无参)
- 编译器不要求必须提供
重载:函数名字一样 参数个数或者类型不一样
析构函数(清理)
- 只能有一个析构函数,不能重载
- 不能带任何参数
- 不能带返回值
- 主要用于清理工作
- 编译器不要求必须提供
如下为析构函数和构造函数例子
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可以称为对象或者实例.
- 可以用父类指针指向子类的对象.
图解:父类指针指向子类的对象.
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);
内存示意图如下:
总结:
- 多重继承增加了程序的复杂度,容易出错
- 微软建议使用单继承,如果需要多重继承可以改为多层继承
- [ebp-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;
}
题目:
#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;
}