this指针
先来看下面代码
#include<iostream>
using namespace std;
class Person
{
public:
void Display()
{
cout<<_name<<"-"<<_age<<"-"<<_id<<endl;
}
public:
char* _name;
int _age;
int _id;
};
int main()
{
Person p;
p._name="jack";
p._age=20;
p._id=123456;
p.Display();
Person *point=&p;
point->_name="Rose";
point->_age=21;
point->_id=654321;
point->Display();
return 0;
}
运行结果
[zyc@localhost lession_class]$ ./a.out
jack-20-123456
Rose-21-654321
为什么调用同样的函数,但是结果却不一样呢?
原因就在于this指针。
下面来看什么是this指针。
1.概念
this指针是一个隐含的指针,它是指向对象本身,代表了对象的地址。
正如你家有个人名叫“狗蛋”的,你隔壁家也有个人叫“狗蛋”。this就表示你自家的人,说明白一点就是你家的那个“狗蛋”。
隐含的指针的说法,可以形象化成这样:
当你进入一个房子后,你可以看见桌子、椅子、地板等,但是房子你是看不到全貌了。
对于一个类的实例来说,你可以看到它的成员函数、成员变量,但是看不到实例本身。
this是一个指针,它时时刻刻指向你这个实例本身。
即使调用相同的构造函数,但是由于调用时传给this指针的实例对象不同,所以打印的对象也就不同,
开始 时this是实例p的地址。随后this是实例point的地址。
2.this特性特性
- 每个成员函数都有一个指针形参,它的名字是固定的,称为this指针,this指针是隐式的。(构造函数和静态成员函数比较特殊,没有这个隐含this形
参)。 - 编译器会对成员函数进行处理,在对象调用成员函数时,对象地址作实参传递给成员函数的第一个形参this指针。
- this指针是成员函数隐含指针形参,是编译器自己处理的,我们不能在成员函数的形参中添加this指针的参数定义,也不能在调用时
显示传递对象的地址给this指针。
4.this指针是实参,调用函数时产生,所以this指针 存放在栈上
5.不可以显示传递this,不识别,可以在函数里面显示写this
6.有些平台为提高效率 将this指针存放在寄存器ecx中,下次要用直接在寄存器中取。比如windows.
类的6个默认成员函数
1.构造函数
成员变量为私有的,要对它们进行初始化,必须用一个公有成员函数来进行。同时这个函数应该有且仅在定义对象时自动执行一次,这时
调用的函数称为构造函数(constructor)。
下面来看代码
1)默认构造函数(编译自动生成)
#include<iostream>
using namespace std;
class Data
{
public:
//无参的构造函数
void Display()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Data d1;
Data d2;
d1.Display();
d2.Display();
return 0;
}
运行结果:
[zyc@localhost lession_class]$ ./a.out
1376536704-32767-0
0-0-4196208
结果分析:
默认构造函数,生成随机值。一旦用户自己定义构造函数,即使时无参的构造函数,系统也不会自动生成构造函数。
2)自定义构造函数
1.无参构造函数
2.带参的构造函数(全缺省参数,半缺省参数)
#include<iostream>
using namespace std;
class Data
{
public:
//无参的构造函数
Data()
{
_year=1900;
_month=1;
_day=1;
}
//带参的构造函数
Data(int year,int month,int day)
{
_year=year;
_month=month;
_day=day;
}
void Display()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Data d1;
Data d2;
//Data d2();无参时,后面不要加括号(直接使用无参的构造函数
//会报错,会被 编译器忽略
Data d3(2018,1,1);
d1.Display();
d2.Display();
d3.Display();
return 0;
}
#include<iostream>
using namespace std;
class Data
{
public:
//Data();不能与下面构造函数共存,否则会报错:调用重载的“Data()”是不明确的
//带参的缺省的构造函数,推荐使用
//传参个数随意
Data(int year=1900,int month=1,int day=1)
{
_year=year;
_month=month;
_day=day;
}
void Display()
{
cout<<_year<<"-"<<_month<<"-"<<_day<<endl;
}
~Data()//析构函数
{
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Data d1;//调用无参的构造函数
Data d2(2018,1,1);//调用带参的构造函数
Data(2018,7,10).Display();//匿名对象
d1.Display();
d2.Display();
return 0;
}
[zyc@localhost lession_class]$ ./a.out
2018-7-10 //匿名对象
1900-1-1 //d1
2018-1-1 //d2
总结构造函数:
构造函数是特殊的成员函数,其特征如下:
- 函数名与类名相同。
- 无返回值。
- 对象构造(对象实例化)时系统自动调用对应的构造函数。
- 构造函数可以重载。
- 构造函数可以在类中定义,也可以在类外定义。
- 如果类定义中没有给出构造函数,则C++编译器自动产生一个缺省的构造函数,但只要我们定义了一个构造函数,系统就不会自动
生成缺省的构造函数。 - 无参的构造函数和全缺省值的构造函数都认为是缺省构造函数,并且缺省的构造函数只能有一个。
- 匿名对象也可以调用构造函数,匿名对象一般是一次性使用的对象。
析构函数
当一个对象的生命周期结束时,C++编译系统会自动调用一个成员函数,这个特殊的成员函数即析构函数(destructor)
构造函数是特殊的成员函数,其特征如下:
1. 析构函数在类名加上字符~。
2. 析构函数无参数无返回值。
3. 一个类有且只有一个析构函数。若未显示定义,系统会自动生成缺省的析构函数。构造函数可以有多个。
4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
5. 注意析构函数体内并不是删除对象,而是做一些清理工作。所谓清理通常指释放一些malloc申请的空间,并将其置为空。防止内存泄露
6. 析构函数不可重载,重载没有实际意义。
#include<iostream>
#include <stdlib.h>
using namespace std;
class Array
{
public:
//构造函数
Array(int size)
{
_ptr=(int *)malloc(size*sizeof(int));
}
//这里的析构函数需要完成清理工作(释放空间)
~Array()
{
if(_ptr)
{
free(_ptr);
_ptr=NULL;
}
}
private:
int *ptr;
};
析构函数总结:
析构函数有自动生成和自定义两种类型。一般有malloc等函数申请空间时最好使用自定义析构函数。
析构函数和构造函数比较
功能 | 函数名 | 产生方式 | 是否可以重载 | 个数限制 |
---|---|---|---|---|
构造函数 | 初始化变量 | 自动生成/自定义 | 可重载 | 一个类可以有多个构造函数 |
析构函数 | 清理工作 | 自动生成/自定义 | 不可重载 | 一个类只有一个析构函数 |